## Automatically generated incremental diff
## From:   linux-2.4.20-pre2
## To:     linux-2.4.20-pre3
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.20-pre2/Documentation/Changes linux-2.4.20-pre3/Documentation/Changes
--- linux-2.4.20-pre2/Documentation/Changes	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/Documentation/Changes	Sat Aug 17 14:18:35 2002
@@ -55,7 +55,7 @@
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
-o  reiserfsprogs          3.x.1b                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.6.3                   # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -225,7 +225,6 @@
 version v0.99.0 or higher. Running old versions may cause problems
 with programs using shared memory.
 
-
 Networking
 ==========
 
diff -urN linux-2.4.20-pre2/Documentation/Configure.help linux-2.4.20-pre3/Documentation/Configure.help
--- linux-2.4.20-pre2/Documentation/Configure.help	Sat Aug 17 14:18:04 2002
+++ linux-2.4.20-pre3/Documentation/Configure.help	Sat Aug 17 14:18:39 2002
@@ -541,7 +541,7 @@
 CONFIG_BLK_STATS
   If you say yes here, your kernel will keep statistical information
   for every partition. The information includes things as numbers of
-  read and write accesses, thenumber of merged requests etc.
+  read and write accesses, the number of merged requests etc.
 
   This is required for the full functionality of sar(8) and interesting
   if you want to do performance tuning, by tweaking the elevator, e.g.
@@ -15031,13 +15031,10 @@
   If you would like to include the NFSv3 server as well as the NFSv2
   server, say Y here.  If unsure, say Y.
 
-Provide NFS over TCP server support DEVELOPER ONLY
+Provide NFS over TCP server support EXPERIMENTAL
 CONFIG_NFSD_TCP
-  If you are a developer and want to work on fixing problems with
-  NFS server over TCP support, say Y here.  If unsure, say N.
-
-  Some problems can be found by looking for FIXME in
-  <file:net/sunrpc/svcsock.c>.
+  Enable NFS service over TCP connections.  This the officially
+  still experimental, but seems to work well.
 
 OS/2 HPFS file system support
 CONFIG_HPFS_FS
@@ -25237,14 +25234,6 @@
   <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
   board at <http://www.mvista.com/allies/semiconductor/ite.html>.
 
-Use chscs for Common I/O
-CONFIG_CHSC
-  Select this option if you want the s390 common I/O layer to use information
-  obtained by channel subsystem calls. This will enable Linux to process link
-  failures and resource accessibility events. Moreover, if you have procfs
-  enabled, you'll be able to toggle chpids logically offline and online. Even
-  if you don't understand what this means, you should say "Y".
-
 Support ARM926T processor
 CONFIG_CPU_ARM926T
   This is a variant of the ARM920.  It has slightly different
@@ -25264,21 +25253,6 @@
   written) to implement the policy. If you don't understand what this
   is all about, it's safe to say 'N'.
 
-Automatic activation of DIAG module
-CONFIG_DASD_AUTO_DIAG
-  Enable this option if you want your DIAG discipline module loaded
-  on DASD driver startup.
-
-Automatic activation of ECKD module
-CONFIG_DASD_AUTO_ECKD
-  Enable this option if you want your ECKD discipline module loaded
-  on DASD driver startup.
-
-Automatic activation of FBA  module
-CONFIG_DASD_AUTO_FBA
-  Enable this option if you want your FBA discipline module loaded
-  on DASD driver startup.
-
 SiS
 CONFIG_DRM_SIS
   Choose this option if you have a SIS graphics card. AGP support is
@@ -25372,16 +25346,6 @@
 
   When in doubt, say N.
 
-Control-Program Identification
-CONFIG_HWC_CPI
-  This option enables the hardware console interface for system
-  identification This is commonly used for workload management and
-  gives you a nice name for the system on the service element.
-  Please select this option as a module since built-in operation is
-  completely untested.
-  You should only select this option if you know what you are doing,
-  need this feature and intend to run your kernel in LPAR.
-
 Enable autotest (llsc). Option to run cache test instead of booting
 CONFIG_IA64_SGI_AUTOTEST
   Build a kernel used for hardware validation. If you include the
@@ -25457,37 +25421,12 @@
   Say Y here to support tuning the ITE8172's IDE interface.  This makes
   it possible to set DMA channel or PIO opration and the transfer rate.
 
-Process warning machine checks
-CONFIG_MACHCHK_WARNING
-  Select this option if you want the machine check handler on IBM S/390 or
-  zSeries to process warning machine checks (e.g. on power failures).
-  If unsure, say "Y".
-
-Pseudo page fault support
-CONFIG_PFAULT
-  Select this option, if you want to use PFAULT pseudo page fault
-  handling under VM. If running native or in LPAR, this option
-  has no effect. If your VM does not support PFAULT, PAGEEX
-  pseudo page fault handling will be used.
-  Note that VM 4.2 supports PFAULT but has a bug in its
-  implementation that causes some problems.
-  Everybody who wants to run Linux under VM != VM4.2 should select
-  this option.
-
 Enable protocol mode for the L1 console
 CONFIG_SERIAL_SGI_L1_PROTOCOL
   Uses protocol mode instead of raw mode for the level 1 console on the
   SGI SN (Scalable NUMA) platform for IA64.  If you are compiling for
   an SGI SN box then Y is the recommended value, otherwise say N.
 
-VM shared kernel support
-CONFIG_SHARED_KERNEL
-  Select this option, if you want to share the text segment of the
-  Linux kernel between different VM guests. This reduces memory
-  usage with lots of guests but greatly increases kernel size.
-  You should only select this option if you know what you are
-  doing and want to exploit this feature.
-
 New bus configuration (EXPERIMENTAL)  
 CONFIG_TULIP_MWI
   This configures your Tulip card specifically for the card and
diff -urN linux-2.4.20-pre2/Documentation/filesystems/isofs.txt linux-2.4.20-pre3/Documentation/filesystems/isofs.txt
--- linux-2.4.20-pre2/Documentation/filesystems/isofs.txt	Wed May 26 10:01:43 1999
+++ linux-2.4.20-pre3/Documentation/filesystems/isofs.txt	Sat Aug 17 14:18:39 2002
@@ -29,3 +29,10 @@
   unhide        Show hidden files.
   session=x     Select number of session on multisession CD
   sbsector=xxx  Session begins from sector xxx
+
+Recommended documents about ISO 9660 standard are located at:
+http://www.y-adagio.com/public/standards/iso_cdromr/tocont.htm
+ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
+Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically 
+identical with ISO 9660.", so it is a valid and gratis substitute of the
+official ISO specification.
diff -urN linux-2.4.20-pre2/Documentation/isdn/README.HiSax linux-2.4.20-pre3/Documentation/isdn/README.HiSax
--- linux-2.4.20-pre2/Documentation/isdn/README.HiSax	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/Documentation/isdn/README.HiSax	Sat Aug 17 14:18:39 2002
@@ -41,9 +41,10 @@
 ELSA Quickstep 3000PCI
 ELSA PCMCIA
 ITK ix1-micro Rev.2
-Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
-Eicon.Diehl Diva 2.01 ISA and PCI
-Eicon.Diehl Diva Piccola
+Eicon Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
+Eicon Diva 2.01 ISA and PCI
+Eicon Diva 2.02 PCI
+Eicon Diva Piccola
 ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
 Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
 PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
@@ -67,13 +68,14 @@
 HFC-PCI based cards
 Winbond W6692 based cards
 HFC-S+, HFC-SP/PCMCIA cards
+formula-n enternow
+Gerdes Power ISDN
 
 Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
       PCC-8: not tested yet
       Eicon.Diehl Diva U interface not tested
 
 If you know other passive cards with the Siemens chipset, please let me know.
-To use the PNP cards you need the isapnptools.
 You can combine any card, if there is no conflict between the resources
 (io, mem, irq).
 
@@ -89,8 +91,15 @@
 modules. It is included in the normal "make [menu]config" target at the
 kernel. Don't forget it, especially to select the right D-channel protocol.
 
-Please note: All PnP cards need to be configured with isapnp and will work
-only with the HiSax driver used as a module.
+Please note: In older versions of the HiSax driver, all PnP cards
+needed to be configured with isapnp and worked only with the HiSax
+driver used as a module.
+
+In the current version, HiSax will automatically use the in-kernel
+ISAPnP support, provided you selected it during kernel configuration
+(CONFIG_ISAPNP), if you don't give the io=, irq= command line parameters.
+
+The affected card types are: 4,7,12,14,19,27-30
 
 a) when built as a module
 -------------------------
@@ -191,6 +200,8 @@
    37	HFC 2BDS0 S+, SP         irq,io 
    38	NETspider U PCI card     none
    39	HFC 2BDS0 SP/PCMCIA      irq,io (set with cardmgr)
+   40   hotplug interface
+   41   Formula-n enter:now PCI  none
 
 At the moment IRQ sharing is only possible with PCI cards. Please make sure
 that your IRQ is free and enabled for ISA use.
@@ -216,6 +227,13 @@
                    (IO 1 (BASE 0x0180))
    modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
 
+   In the current version of HiSax, you can instead simply use
+
+   modprobe hisax type=4 protocol=2
+
+   if you configured your kernel for ISAPnP. Don't run isapnp in
+   this case!
+
 6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
    Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
    modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
@@ -296,7 +314,9 @@
    36	W6692 based PCI cards   none
    37	HFC 2BDS0 S+,SP/PCMCIA  ONLY WORKS AS A MODULE !
    38	NETspider U PCI card    none
-
+   39	HFC 2BDS0 SP/PCMCIA     ONLY WORKS AS A MODULE !
+   40   hotplug interface	ONLY WORKS AS A MODULE !
+   41   Formula-n enter:now PCI none
 
 Running the driver
 ------------------
diff -urN linux-2.4.20-pre2/Documentation/sysctl/vm.txt linux-2.4.20-pre3/Documentation/sysctl/vm.txt
--- linux-2.4.20-pre2/Documentation/sysctl/vm.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/Documentation/sysctl/vm.txt	Sat Aug 17 14:18:39 2002
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/vm/*	kernel version 2.2.10
+Documentation for /proc/sys/vm/*	kernel version 2.4.19
 	(c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 For general info and legal blurb, please look in README.
@@ -6,7 +6,7 @@
 ==============================================================
 
 This file contains the documentation for the sysctl files in
-/proc/sys/vm and is valid for Linux kernel version 2.2.
+/proc/sys/vm and is valid for Linux kernel version 2.4.
 
 The files in this directory can be used to tune the operation
 of the virtual memory (VM) subsystem of the Linux kernel, and
@@ -34,26 +34,27 @@
 This file controls the operation of the bdflush kernel
 daemon. The source code to this struct can be found in
 linux/fs/buffer.c. It currently contains 9 integer values,
-of which 4 are actually used by the kernel.
+of which 6 are actually used by the kernel.
 
 From linux/fs/buffer.c:
 --------------------------------------------------------------
 union bdflush_param {
 	struct {
-		int nfract;	/* Percentage of buffer cache dirty to 
+		int nfract;	/* Percentage of buffer cache dirty to
 				   activate bdflush */
-		int dummy1;	/* old "ndirty" */
+		int ndirty;	/* Maximum number of dirty blocks to write out per
+				   wake-cycle */
 		int dummy2;	/* old "nrefill" */
 		int dummy3;	/* unused */
 		int interval;	/* jiffies delay between kupdate flushes */
-		int age_buffer;	/* Time for normal buffer to age */
-		int nfract_sync;/* Percentage of buffer cache dirty to 
+		int age_buffer;	/* Time for normal buffer to age before we flush it */
+		int nfract_sync;/* Percentage of buffer cache dirty to
 				   activate bdflush synchronously */
-		int dummy4;	/* unused */
+		int nfract_stop_bdflush; /* Percentage of buffer cache dirty to stop bdflush */
 		int dummy5;	/* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{30, 500, 0, 0, 5*HZ, 30*HZ, 60, 20, 0}};
 --------------------------------------------------------------
 
 int nfract:
@@ -68,6 +69,13 @@
 more frequent I/O operations.  The default value is 30%,
 the minimum is 0%, and the maximum is 100%.
 
+int ndirty:
+The second parameter (ndirty) gives the maximum number of
+dirty buffers that bdflush can write to the disk in one time.
+A high value will mean delayed, bursty I/O, while a small
+value can lead to memory shortage when bdflush isn't woken
+up often enough.
+
 int interval:
 The fifth parameter, interval, is the minimum rate at
 which kupdate will wake and flush.  The value is expressed in
@@ -88,7 +96,11 @@
 synchronously.  This can be viewed as the hard limit before
 bdflush forces buffers to disk.  The default is 60%, the
 minimum is 0%, and the maximum is 100%.
- 
+
+int nfract_stop_bdflush:
+The eighth parameter, nfract_stop_bdflush, governs the percentage
+of buffer cache that is dirty which will stop bdflush.
+The default is 20%, the miniumum is 0%, and the maxiumum is 100%.
 ==============================================================
 buffermem:
 
diff -urN linux-2.4.20-pre2/MAINTAINERS linux-2.4.20-pre3/MAINTAINERS
--- linux-2.4.20-pre2/MAINTAINERS	Sat Aug 17 14:18:06 2002
+++ linux-2.4.20-pre3/MAINTAINERS	Sat Aug 17 14:18:40 2002
@@ -1,3 +1,4 @@
+	
 	List of maintainers and how to submit kernel changes
 
 Please try to follow the guidelines below.  This will make things
@@ -241,6 +242,12 @@
 W:	http://www.ife.ee.ethz.ch/~sailer/ham/ham.html
 S:	Maintained
 
+BEFS FILE SYSTEM
+P:	Will Dyson
+M:	will@cs.earlham.edu
+W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+S:	Maintained
+
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
 P:	Kenji Hollis
 M:	kenji@bitgate.com
@@ -632,8 +639,8 @@
 S:	Maintained
 
 HFS FILESYSTEM
-P:      Adrian Sun
-M:      asun@cobaltnet.com
+P:      Oliver Neukum
+M:      oliver@neukum.org
 L:      linux-kernel@vger.kernel.org
 S:      Maintained
 
@@ -710,8 +717,10 @@
 S:	Maintained
 
 IBM ServeRAID RAID DRIVER
-P:      Keith Mitchell
-M:      ipslinux@us.ibm.com
+P:      Jack Hammer
+M:      ipslinux@adaptec.com
+P:      David Jeffery
+M:      ipslinux@adaptec.com
 W:      http://www.developer.ibm.com/welcome/netfinity/serveraid.html
 S:      Supported 
 
@@ -1101,7 +1110,6 @@
 P:	Networking Team
 M:	netdev@oss.sgi.com
 L:	linux-net@vger.kernel.org
-W:	http://www.uk.linux.org/NetNews.html (2.0 only)
 S:	Maintained
 
 NETWORKING [IPv4/IPv6]
@@ -1357,10 +1365,10 @@
 S:	Maintained
 
 RME96XX MULTICHANNEL SOUND DRIVER
-P:      Guenter Geiger
-M:      geiger@epy.co.at  
-L:      linux-kernel@vger.kernel.org
-S:      Maintained
+P:	Guenter Geiger
+M:	geiger@epy.co.at  
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
 
 RTLINUX  REALTIME  LINUX
 P:	Victor Yodaiken
diff -urN linux-2.4.20-pre2/Makefile linux-2.4.20-pre3/Makefile
--- linux-2.4.20-pre2/Makefile	Sat Aug 17 14:18:06 2002
+++ linux-2.4.20-pre3/Makefile	Sat Aug 17 14:18:40 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -pre2
+EXTRAVERSION = -pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -180,11 +180,13 @@
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
 DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o
 DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
 DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
 DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
diff -urN linux-2.4.20-pre2/arch/alpha/kernel/pci.c linux-2.4.20-pre3/arch/alpha/kernel/pci.c
--- linux-2.4.20-pre2/arch/alpha/kernel/pci.c	Fri Nov  2 17:39:20 2001
+++ linux-2.4.20-pre3/arch/alpha/kernel/pci.c	Sat Aug 17 14:18:40 2002
@@ -351,7 +351,7 @@
 }
 
 int
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	/* Nothing to do, since we enable all devices at startup.  */
 	return 0;
diff -urN linux-2.4.20-pre2/arch/alpha/mm/fault.c linux-2.4.20-pre3/arch/alpha/mm/fault.c
--- linux-2.4.20-pre2/arch/alpha/mm/fault.c	Mon Sep 17 16:15:02 2001
+++ linux-2.4.20-pre3/arch/alpha/mm/fault.c	Sat Aug 17 14:18:40 2002
@@ -88,6 +88,7 @@
 	struct mm_struct *mm = current->mm;
 	unsigned int fixup;
 	int fault;
+	siginfo_t info;
 
 	/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
 	   (or is suppressed by the PALcode).  Support that for older CPUs
@@ -108,6 +109,8 @@
 	if (!mm || in_interrupt())
 		goto no_context;
 
+	info.si_code = SEGV_MAPERR;
+
 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
 	if (address >= TASK_SIZE)
 		goto vmalloc_fault;
@@ -128,6 +131,7 @@
  * we can handle it..
  */
 good_area:
+	info.si_code = SEGV_ACCERR;
 	if (cause < 0) {
 		if (!(vma->vm_flags & VM_EXEC))
 			goto bad_area;
@@ -164,7 +168,12 @@
 	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
-		force_sig(SIGSEGV, current);
+			
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		/* info.si_code has been set above */
+		info.si_addr = (void *)address;
+		force_sig_info(SIGSEGV,&info,current);
 		return;
 	}
 
@@ -196,8 +205,7 @@
  */
 out_of_memory:
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
@@ -212,7 +220,12 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	force_sig(SIGBUS, current);
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	/* not sure si_code value here  */
+	info.si_code =  BUS_ADRERR;
+	info.si_addr = (void *)address;
+	force_sig_info(SIGBUS,&info,current);
 	if (!user_mode(regs))
 		goto no_context;
 	return;
@@ -220,7 +233,11 @@
 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
 vmalloc_fault:
 	if (user_mode(regs)) {
-		force_sig(SIGSEGV, current);
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		/* info.si_code has been set above */
+		info.si_addr = (void *)address;
+		force_sig_info(SIGSEGV,&info,current);
 		return;
 	} else {
 		/* Synchronize this task's top level page-table
diff -urN linux-2.4.20-pre2/arch/arm/mach-integrator/cpu.c linux-2.4.20-pre3/arch/arm/mach-integrator/cpu.c
--- linux-2.4.20-pre2/arch/arm/mach-integrator/cpu.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.20-pre3/arch/arm/mach-integrator/cpu.c	Sat Aug 17 14:18:40 2002
@@ -121,7 +121,7 @@
 	cpu_freq_khz = vco_to_freq(vco, 1);
 
 #ifdef CONFIG_CPU_FREQ
-	cpufreq_init(cpu_freq_khz);
+	cpufreq_init(cpu_freq_khz, 1000, 0);
 	cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
 #endif
 
diff -urN linux-2.4.20-pre2/arch/arm/mach-sa1100/generic.c linux-2.4.20-pre3/arch/arm/mach-sa1100/generic.c
--- linux-2.4.20-pre2/arch/arm/mach-sa1100/generic.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/arm/mach-sa1100/generic.c	Sat Aug 17 14:18:40 2002
@@ -86,7 +86,7 @@
 
 static int __init sa11x0_init_clock(void)
 {
-	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100);
+	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100, 0, 0);
 	return 0;
 }
 
diff -urN linux-2.4.20-pre2/arch/arm/mm/fault-common.c linux-2.4.20-pre3/arch/arm/mm/fault-common.c
--- linux-2.4.20-pre2/arch/arm/mm/fault-common.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/arm/mm/fault-common.c	Sat Aug 17 14:18:40 2002
@@ -225,8 +225,7 @@
 	 * If we are out of memory for pid1,
 	 * sleep for a while and retry
 	 */
-	tsk->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	goto survive;
 
 check_stack:
diff -urN linux-2.4.20-pre2/arch/cris/config.in linux-2.4.20-pre3/arch/cris/config.in
--- linux-2.4.20-pre2/arch/cris/config.in	Sat Aug 17 14:18:06 2002
+++ linux-2.4.20-pre3/arch/cris/config.in	Sat Aug 17 14:18:40 2002
@@ -39,6 +39,8 @@
 	bool 'Disable watchdog during Oops printouts' CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
 fi
 
+bool 'Enable ETRAX fast timer API' CONFIG_ETRAX_FAST_TIMER
+
 endmenu
 
 mainmenu_option next_comment
diff -urN linux-2.4.20-pre2/arch/cris/drivers/Config.in linux-2.4.20-pre3/arch/cris/drivers/Config.in
--- linux-2.4.20-pre2/arch/cris/drivers/Config.in	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/drivers/Config.in	Sat Aug 17 14:18:40 2002
@@ -23,8 +23,7 @@
 
 bool 'Serial-port support' CONFIG_ETRAX_SERIAL
 if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
-#  bool '  Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n
-  define_bool CONFIG_ETRAX_SERIAL_FAST_TIMER n
+  bool '  Use fast timers for serial DMA flush (experimental)' CONFIG_ETRAX_SERIAL_FAST_TIMER
   if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then
     bool '  Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
     if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
@@ -156,6 +155,11 @@
 # this is true for most products since PB-I2C seems to be somewhat
 # flawed.. 
 	bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+
+	if [ "$CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C" = "y" ]; then
+          int '  I2C SDA bit number' CONFIG_ETRAX_I2C_DATA_PORT 0
+          int '  I2C SCL bit number' CONFIG_ETRAX_I2C_CLK_PORT 1
+	fi
 fi
 
 bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM
@@ -182,6 +186,8 @@
 
 fi
 
+bool 'VIRTEX FPGA support' CONFIG_ETRAX_VIRTEX_FPGA
+
 bool 'USB host' CONFIG_ETRAX_USB_HOST
 if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
 	define_bool CONFIG_USB y
@@ -191,7 +197,13 @@
 	define_bool CONFIG_USB n
 fi
 
-bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302
+bool 'Real Time Clock support' CONFIG_ETRAX_RTC
+if [ "$CONFIG_ETRAX_RTC" = "y" ]; then
+  choice '  RTC chip' \
+    "DS1302 CONFIG_ETRAX_DS1302 \
+     PCF8563  CONFIG_ETRAX_PCF8563" DS1302
+fi
+
 if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then
   bool '  DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
diff -urN linux-2.4.20-pre2/arch/cris/drivers/Makefile linux-2.4.20-pre3/arch/cris/drivers/Makefile
--- linux-2.4.20-pre2/arch/cris/drivers/Makefile	Wed Jul  4 11:50:38 2001
+++ linux-2.4.20-pre3/arch/cris/drivers/Makefile	Sat Aug 17 14:18:40 2002
@@ -6,7 +6,7 @@
 
 obj-y :=
 
-
+obj-$(CONFIG_ETRAX_VIRTEX_FPGA)         += virtex.o
 obj-$(CONFIG_ETRAX_ETHERNET)            += ethernet.o
 obj-$(CONFIG_ETRAX_SERIAL)              += serial.o
 obj-$(CONFIG_ETRAX_IDE)                 += ide.o
diff -urN linux-2.4.20-pre2/arch/cris/drivers/ds1302.c linux-2.4.20-pre3/arch/cris/drivers/ds1302.c
--- linux-2.4.20-pre2/arch/cris/drivers/ds1302.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/drivers/ds1302.c	Sat Aug 17 14:18:40 2002
@@ -7,6 +7,9 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.13  2002/05/29 15:16:08  johana
+*! Removed unused variables.
+*!
 *! Revision 1.12  2002/04/10 15:35:25  johana
 *! Moved probe function closer to init function and marked it __init.
 *!
@@ -85,7 +88,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.12 2002/04/10 15:35:25 johana Exp $
+*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -322,7 +325,6 @@
 		{
 			struct rtc_time rtc_tm;
 			unsigned char mon, day, hrs, min, sec, leap_yr;
-			unsigned char save_control, save_freq_select;
 			unsigned int yrs;
 
 			if (!capable(CAP_SYS_TIME))
@@ -386,7 +388,6 @@
 		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
 		{
 			int tcs_val;                        
-			unsigned char save_control, save_freq_select;
 
 			if (!capable(CAP_SYS_TIME))
 				return -EPERM;
diff -urN linux-2.4.20-pre2/arch/cris/drivers/gpio.c linux-2.4.20-pre3/arch/cris/drivers/gpio.c
--- linux-2.4.20-pre2/arch/cris/drivers/gpio.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/drivers/gpio.c	Sat Aug 17 14:18:40 2002
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.15 2002/05/06 13:19:13 johana Exp $
+/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,18 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.17  2002/06/17 15:53:01  johana
+ * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
+ * that take a pointer as argument and thus can handle 32 bit ports (G)
+ * correctly.
+ * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT.
+ * (especially if Port G bit 31 is used)
+ *
+ * Revision 1.16  2002/06/17 09:59:51  johana
+ * Returning 32 bit values in the ioctl return value doesn't work if bit
+ * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF.
+ * A new set of ioctl's will be added.
+ *
  * Revision 1.15  2002/05/06 13:19:13  johana
  * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
  *
@@ -330,6 +342,107 @@
  * set alarms to wait for using a subsequent select().
  */
 
+unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+{
+	/* Set direction 0=unchanged 1=input, 
+	 * return mask with 1=input 
+	 */
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		save_flags(flags); cli();
+		*priv->dir = *priv->dir_shadow &= 
+		~((unsigned char)arg & priv->changeable_dir);
+		restore_flags(flags);
+		return ~(*priv->dir_shadow);
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */
+		if (((arg & dir_g_in_bits) != arg) && 
+		    (arg & changeable_dir_g)) {
+			arg &= changeable_dir_g;
+			/* Clear bits in genconfig to set to input */
+			if (arg & (1<<0)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_in_bits |= (1<<0);
+				dir_g_out_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_in_bits |= 0x0000FF00;
+				dir_g_out_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_in_bits |= 0x00FF0000;
+				dir_g_out_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_in_bits |= (1<<24);
+				dir_g_out_bits &= ~(1<<24);
+			}
+			printk("gpio: SETINPUT on port G set "
+				"genconfig to 0x%08lX "
+				"in_bits: 0x%08lX "
+				"out_bits: 0x%08lX\n", 
+			       (unsigned long)genconfig_shadow, 
+			       dir_g_in_bits, dir_g_out_bits);
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+				
+		}
+		return dir_g_in_bits;
+	}
+	return 0;
+} /* setget_input */
+
+unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
+{
+	unsigned long flags;
+	if (USE_PORTS(priv)) {
+		save_flags(flags); cli();
+		*priv->dir = *priv->dir_shadow |= 
+		  ((unsigned char)arg & priv->changeable_dir);
+		restore_flags(flags);
+		return *priv->dir_shadow;
+	} else if (priv->minor == GPIO_MINOR_G) {
+		/* We must fiddle with R_GEN_CONFIG to change dir */			
+		if (((arg & dir_g_out_bits) != arg) &&
+		    (arg & changeable_dir_g)) {
+			/* Set bits in genconfig to set to output */
+			if (arg & (1<<0)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
+				dir_g_out_bits |= (1<<0);
+				dir_g_in_bits &= ~(1<<0);
+			}
+			if ((arg & 0x0000FF00) == 0x0000FF00) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
+				dir_g_out_bits |= 0x0000FF00;
+				dir_g_in_bits &= ~0x0000FF00;
+			}
+			if ((arg & 0x00FF0000) == 0x00FF0000) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
+				dir_g_out_bits |= 0x00FF0000;
+				dir_g_in_bits &= ~0x00FF0000;
+			}
+			if (arg & (1<<24)) {
+				genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
+				dir_g_out_bits |= (1<<24);
+				dir_g_in_bits &= ~(1<<24);
+			}
+			printk("gpio: SETOUTPUT on port G set "
+				"genconfig to 0x%08lX "
+				"in_bits: 0x%08lX "
+				"out_bits: 0x%08lX\n", 
+			       (unsigned long)genconfig_shadow, 
+			       dir_g_in_bits, dir_g_out_bits);
+			*R_GEN_CONFIG = genconfig_shadow;
+			/* Must be a >120 ns delay before writing this again */
+		}
+		return dir_g_out_bits & 0x7FFFFFFF;
+	}
+	return 0;
+} /* setget_output */
+
 static int
 gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
 
@@ -338,18 +451,19 @@
 	   unsigned int cmd, unsigned long arg)
 {
 	unsigned long flags;
+	unsigned long val;
 	struct gpio_private *priv = (struct gpio_private *)file->private_data;
 	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
 		return -EINVAL;
 	}
 
 	switch (_IOC_NR(cmd)) {
-	case IO_READBITS:
+	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
 		// read the port
 		if (USE_PORTS(priv)) {
 			return *priv->port;
 		} else if (priv->minor == GPIO_MINOR_G) {
-			return *R_PORT_G_DATA;
+			return (*R_PORT_G_DATA) & 0x7FFFFFFF;
 		}
 		break;
 	case IO_SETBITS:
@@ -387,113 +501,28 @@
 		priv->highalarm &= ~arg;
 		priv->lowalarm  &= ~arg;
 		break;
-	case IO_READDIR:
+	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
 		/* Read direction 0=input 1=output */
 		if (USE_PORTS(priv)) {
 			return *priv->dir_shadow;
 		} else if (priv->minor == GPIO_MINOR_G) {
 			/* Note: Some bits are both in and out,
-			 * Those that are dual is set hare as well.
+			 * Those that are dual is set here as well.
 			 */
-			return dir_g_shadow | dir_g_out_bits;
+			return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
 		}
-	case IO_SETINPUT:
+	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
 		/* Set direction 0=unchanged 1=input, 
 		 * return mask with 1=input 
 		 */
-		if (USE_PORTS(priv)) {
-			save_flags(flags); cli();
-			*priv->dir = *priv->dir_shadow &= 
-			~((unsigned char)arg & priv->changeable_dir);
-			restore_flags(flags);
-			return ~(*priv->dir_shadow);
-		} else if (priv->minor == GPIO_MINOR_G) {
-			/* We must fiddle with R_GEN_CONFIG to change dir */
-			if (((arg & dir_g_in_bits) != arg) && 
-			    (arg & changeable_dir_g)) {
-				arg &= changeable_dir_g;
-				/* Clear bits in genconfig to set to input */
-				if (arg & (1<<0)) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
-					dir_g_in_bits |= (1<<0);
-					dir_g_out_bits &= ~(1<<0);
-				}
-				if ((arg & 0x0000FF00) == 0x0000FF00) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
-					dir_g_in_bits |= 0x0000FF00;
-					dir_g_out_bits &= ~0x0000FF00;
-				}
-				if ((arg & 0x00FF0000) == 0x00FF0000) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
-					dir_g_in_bits |= 0x00FF0000;
-					dir_g_out_bits &= ~0x00FF0000;
-				}
-				if (arg & (1<<24)) {
-					genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
-					dir_g_in_bits |= (1<<24);
-					dir_g_out_bits &= ~(1<<24);
-				}
-				printk("gpio: SETINPUT on port G set "
-					"genconfig to 0x%08lX "
-					"in_bits: 0x%08lX "
-					"out_bits: 0x%08lX\n", 
-				       (unsigned long)genconfig_shadow, 
-				       dir_g_in_bits, dir_g_out_bits);
-				*R_GEN_CONFIG = genconfig_shadow;
-				/* Must be a >120 ns delay before writing this again */
-				
-			}
-			return dir_g_in_bits;
-		}
-		return 0;
-
-	case IO_SETOUTPUT:
+		return setget_input(priv, arg) & 0x7FFFFFFF;
+		break;
+	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
 		/* Set direction 0=unchanged 1=output, 
 		 * return mask with 1=output 
 		 */
-		if (USE_PORTS(priv)) {
-			save_flags(flags); cli();
-			*priv->dir = *priv->dir_shadow |= 
-			  ((unsigned char)arg & priv->changeable_dir);
-			restore_flags(flags);
-			return *priv->dir_shadow;
-		} else if (priv->minor == GPIO_MINOR_G) {
-			/* We must fiddle with R_GEN_CONFIG to change dir */			
-			if (((arg & dir_g_out_bits) != arg) &&
-			    (arg & changeable_dir_g)) {
-				/* Set bits in genconfig to set to output */
-				if (arg & (1<<0)) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
-					dir_g_out_bits |= (1<<0);
-					dir_g_in_bits &= ~(1<<0);
-				}
-				if ((arg & 0x0000FF00) == 0x0000FF00) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
-					dir_g_out_bits |= 0x0000FF00;
-					dir_g_in_bits &= ~0x0000FF00;
-				}
-				if ((arg & 0x00FF0000) == 0x00FF0000) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
-					dir_g_out_bits |= 0x00FF0000;
-					dir_g_in_bits &= ~0x00FF0000;
-				}
-				if (arg & (1<<24)) {
-					genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
-					dir_g_out_bits |= (1<<24);
-					dir_g_in_bits &= ~(1<<24);
-				}
-				printk("gpio: SETOUTPUT on port G set "
-					"genconfig to 0x%08lX "
-					"in_bits: 0x%08lX "
-					"out_bits: 0x%08lX\n", 
-				       (unsigned long)genconfig_shadow, 
-				       dir_g_in_bits, dir_g_out_bits);
-				*R_GEN_CONFIG = genconfig_shadow;
-				/* Must be a >120 ns delay before writing this again */
-			}
-			return dir_g_out_bits;
-		}
-		return 0;
+		return setget_output(priv, arg) & 0x7FFFFFFF;
+
 	case IO_SHUTDOWN:
 		SOFT_SHUTDOWN();
 		break;
@@ -521,6 +550,47 @@
 			return -EPERM;
 		}
 		break;
+	case IO_READ_INBITS: 
+		/* *arg is result of reading the input pins */
+		if (USE_PORTS(priv)) {
+			val = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = *R_PORT_G_DATA;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		return 0;
+		break;
+	case IO_READ_OUTBITS:
+		 /* *arg is result of reading the output shadow */
+		if (USE_PORTS(priv)) {
+			val = *priv->shadow;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			val = port_g_data_shadow;
+		}
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_INPUT: 
+		/* bits set in *arg is set to input,
+		 * *arg updated with current input pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_input(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
+	case IO_SETGET_OUTPUT:
+		/* bits set in *arg is set to output,
+		 * *arg updated with current output pins.
+		 */
+		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+			return -EFAULT;
+		val = setget_output(priv, val);
+		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+			return -EFAULT;
+		break;
 	default:
 		if (priv->minor == GPIO_MINOR_LEDS)
 			return gpio_leds_ioctl(cmd, arg);
@@ -690,7 +760,7 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.3, (c) 2001, 2002 Axis Communications AB\n");
+	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
 
 	return res;
 }
diff -urN linux-2.4.20-pre2/arch/cris/drivers/i2c.c linux-2.4.20-pre3/arch/cris/drivers/i2c.c
--- linux-2.4.20-pre2/arch/cris/drivers/i2c.c	Sat May 19 17:43:05 2001
+++ linux-2.4.20-pre3/arch/cris/drivers/i2c.c	Sat Aug 17 14:18:40 2002
@@ -12,6 +12,10 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.8  2002/08/13 06:31:53  starvik
+*! Made SDA and SCL line configurable
+*! Modified i2c_inbyte to work with PCF8563
+*!
 *! Revision 1.7  2001/04/04 13:11:36  markusl
 *! Updated according to review remarks
 *!
@@ -40,10 +44,10 @@
 *!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
+*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.7 2001/04/04 13:11:36 markusl Exp $ */
+/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -93,8 +97,15 @@
 
 #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
 /* Use PB and not PB_I2C */
-#define SDABIT 0
-#define SCLBIT 1
+#ifndef CONFIG_ETRAX_I2C_DATA_PORT
+#define CONFIG_ETRAX_I2C_DATA_PORT 0
+#endif
+#ifndef CONFIG_ETRAX_I2C_CLK_PORT
+#define CONFIG_ETRAX_I2C_CLK_PORT 1
+#endif
+
+#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT
+#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT
 #define i2c_enable() 
 #define i2c_disable() 
 
@@ -114,7 +125,7 @@
 
 /* read a bit from the i2c interface */
 
-#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT))
+#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT)
 
 #else
 /* enable or disable the i2c interface */
@@ -206,7 +217,7 @@
 i2c_outbyte(unsigned char x)
 {
 	int i;
-	
+
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
@@ -238,65 +249,44 @@
 {
 	unsigned char aBitByte = 0;
 	int i;
-	int iaa;
 
-	/*
-	 * enable output
-	 */
-	i2c_dir_out();
-	/*
-	 * Release data bus by setting
-	 * data high
-	 */
-	i2c_data(I2C_DATA_HIGH);
-	/*
-	 * enable input
-	 */
+	/* Switch off I2C to get bit */
+	i2c_disable();
 	i2c_dir_in();
-	/*
-	 * Use PORT PB instead of I2C
-	 * for input. (I2C not working)
-	 */
-	i2c_clk(1);
-	i2c_data(1);
-	/*
-	 * get bits
-	 */
-	for (i = 0; i < 8; i++) {
-		i2c_delay(CLOCK_LOW_TIME/2);
-		/*
-		 * low clock period
-		 */
+	i2c_delay(CLOCK_HIGH_TIME/2);
+
+	/* Get bit */
+	aBitByte |= i2c_getbit();
+
+	/* Enable I2C */
+	i2c_enable();
+	i2c_dir_out();
+	i2c_delay(CLOCK_LOW_TIME/2);
+
+	for (i = 1; i < 8; i++) {
+		aBitByte <<= 1;
+		/* Clock pulse */
 		i2c_clk(I2C_CLOCK_HIGH);
-		/*
-		 * switch off I2C
-		 */
-		i2c_data(1);
+		i2c_delay(CLOCK_HIGH_TIME);
+		i2c_clk(I2C_CLOCK_LOW);
+		i2c_delay(CLOCK_LOW_TIME);
+
+		/* Switch off I2C to get bit */
 		i2c_disable();
 		i2c_dir_in();
-		/*
-		 * wait before getting bit
-		 */
-		i2c_delay(CLOCK_HIGH_TIME/2);
-		aBitByte = (aBitByte << 1);
-		iaa = i2c_getbit();
-		aBitByte = aBitByte | iaa ;
-		/*
-		 * wait
-		 */
 		i2c_delay(CLOCK_HIGH_TIME/2);
-		/*
-		 * end clock puls
-		 */
+
+		/* Get bit */
+		aBitByte |= i2c_getbit();
+
+		/* Enable I2C */
 		i2c_enable();
 		i2c_dir_out();
-		i2c_clk(I2C_CLOCK_LOW);
-		/*
-		 * low clock period
-		 */
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
-	i2c_dir_out();
+	i2c_clk(I2C_CLOCK_HIGH);
+	i2c_delay(CLOCK_HIGH_TIME);
+	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -421,7 +411,7 @@
 *#
 *#--------------------------------------------------------------------------*/
 int
-i2c_writereg(unsigned char theSlave, unsigned char theReg,
+i2c_writereg(unsigned char theSlave, unsigned char theReg, 
 	     unsigned char theValue)
 {
 	int error, cntr = 3;
@@ -434,31 +424,12 @@
 		 */
 		save_flags(flags);
 		cli();
-		/*
-		 * generate start condition
-		 */
-		i2c_start();
-		/*
-		 * dummy preamble
-		 */
-		i2c_outbyte(0x01);
-		i2c_data(I2C_DATA_HIGH);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
-		i2c_data(I2C_DATA_LOW);
-		i2c_delay(CLOCK_HIGH_TIME);
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
 
 		i2c_start();
 		/*
 		 * send slave address
 		 */
-		i2c_outbyte(theSlave);
+		i2c_outbyte((theSlave & 0xfe));
 		/*
 		 * wait for ack
 		 */
@@ -493,7 +464,7 @@
 		restore_flags(flags);
 		
 	} while(error && cntr--);
-	
+
 	i2c_delay(CLOCK_LOW_TIME);
 	
 	return -error;
@@ -512,7 +483,7 @@
 	unsigned char b = 0;
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
@@ -524,28 +495,11 @@
 		 * generate start condition
 		 */
 		i2c_start();
-		/*
-		 * dummy preamble
-		 */
-		i2c_outbyte(0x01);
-		i2c_data(I2C_DATA_HIGH);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-		i2c_clk(I2C_CLOCK_HIGH);
-		i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */
-		i2c_data(I2C_DATA_LOW);
-		i2c_delay(CLOCK_HIGH_TIME);
-		i2c_clk(I2C_CLOCK_LOW);
-		i2c_delay(CLOCK_LOW_TIME);
-    
-		i2c_start();
     
 		/*
 		 * send slave address
 		 */
-		i2c_outbyte(theSlave);
+		i2c_outbyte((theSlave & 0xfe));
 		/*
 		 * wait for ack
 		 */
diff -urN linux-2.4.20-pre2/arch/cris/drivers/pcf8563.c linux-2.4.20-pre3/arch/cris/drivers/pcf8563.c
--- linux-2.4.20-pre2/arch/cris/drivers/pcf8563.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/arch/cris/drivers/pcf8563.c	Sat Aug 17 14:18:40 2002
@@ -0,0 +1,258 @@
+/*
+ * PCF8563 RTC
+ *
+ * From Phillips' datasheet:
+ *
+ * The PCF8563 is a CMOS real-time clock/calendar optimized for low power
+ * consumption. A programmable clock output, interupt output and voltage
+ * low detector are also provided. All address and data are transferred
+ * serially via two-line bidirectional I2C-bus. Maximum bus speed is
+ * 400 kbits/s. The built-in word address register is incremented
+ * automatically after each written or read bute.
+ *
+ * Copyright (c) 2002, Axis Communications AB
+ * All rights reserved.
+ *
+ * Author: Tobias Anderberg <tobiasa@axis.com>.
+ *
+ * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/svinto.h>
+#include <asm/rtc.h>
+#include "i2c.h"
+
+#define PCF8563_MAJOR 121		/* Local major number. */
+#define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
+#define PCF8563_NAME "PCF8563"
+#define DRIVER_VERSION "$Rev$"
+
+/* Two simple wrapper macros, saves a few keystrokes. */
+#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
+#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
+	
+static const unsigned char days_in_month[] =
+	{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int pcf8563_open(struct inode *, struct file *);
+int pcf8563_release(struct inode *, struct file *);
+
+static struct file_operations pcf8563_fops = {
+	owner: THIS_MODULE,
+	ioctl: pcf8563_ioctl,
+	open: pcf8563_open,
+	release: pcf8563_release,
+};
+
+void
+get_rtc_time(struct rtc_time *tm)
+{
+	unsigned long flags;
+	
+	tm->tm_sec = rtc_read(RTC_SECONDS);
+	tm->tm_min = rtc_read(RTC_MINUTES);
+	tm->tm_hour = rtc_read(RTC_HOURS);
+	tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH);
+	tm->tm_mon = rtc_read(RTC_MONTH);
+	tm->tm_year = rtc_read(RTC_YEAR);
+
+	if (tm->tm_sec & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+
+        tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_sec &= 0x7f;
+	tm->tm_min &= 0x7f;
+	tm->tm_hour &= 0x3f;
+	tm->tm_mday &= 0x3f;
+	tm->tm_mon &= 0x1f;
+
+	BCD_TO_BIN(tm->tm_sec);
+	BCD_TO_BIN(tm->tm_min);
+	BCD_TO_BIN(tm->tm_hour);
+	BCD_TO_BIN(tm->tm_mday);
+	BCD_TO_BIN(tm->tm_mon);
+	tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */
+}
+
+int __init
+pcf8563_init(void)
+{
+	unsigned char ret;
+        struct rtc_time tm;
+        
+	/*
+	 * First of all we need to reset the chip. This is done by
+	 * clearing control1, control2 and clk freq, clear the 
+	 * Voltage Low bit, and resetting all alarms.
+	 */
+	if (rtc_write(RTC_CONTROL1, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CONTROL2, 0x00) < 0)
+		goto err;
+
+	if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0)
+		goto err;
+
+	/* Clear the VL bit in the seconds register. */
+	ret = rtc_read(RTC_SECONDS);
+	
+	if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0)
+		goto err;
+		
+	/* Reset the alarms. */
+	if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_DAY_ALARM, 0x00) < 0)
+		goto err;
+	
+	if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
+		goto err;
+
+	if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
+		printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n", 
+		       PCF8563_NAME, PCF8563_MAJOR);
+		return -1;
+	}
+
+	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+        
+	/* Check for low voltage, and warn about it.. */
+	if (rtc_read(RTC_SECONDS) & 0x80)
+		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
+	
+	return 0;
+
+err:
+	printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
+	return -1;
+}
+
+void __exit
+pcf8563_exit(void)
+{
+	if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
+		printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
+	}
+}
+
+/*
+ * ioctl calls for this driver. Why return -ENOTTY upon error? Because
+ * POSIX says so!
+ */
+int
+pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	/* Some sanity checks. */
+	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
+		return -ENOTTY;
+
+	switch (cmd) {
+		case RTC_RD_TIME:
+			{
+				struct rtc_time tm;
+
+				get_rtc_time(&tm);
+
+				if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
+					return -EFAULT;
+				}
+
+				return 0;
+			}
+			break;
+		case RTC_SET_TIME:
+			{
+				int leap;
+				int century;
+				unsigned long flags;
+				struct rtc_time tm;
+
+				if (!capable(CAP_SYS_TIME))
+					return -EPERM;
+
+				if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time)))
+					return -EFAULT;
+
+				/* Convert from struct tm to struct rtc_time. */
+				tm.tm_year += 1900;
+				tm.tm_mon += 1;
+				
+				leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0;
+
+				/* Perform some sanity checks. */
+				if ((tm.tm_year < 1970) ||
+				    (tm.tm_mon > 12) ||
+				    (tm.tm_mday == 0) ||
+				    (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
+				    (tm.tm_hour >= 24) ||
+				    (tm.tm_min >= 60) ||
+				    (tm.tm_sec >= 60))
+					return -EINVAL;
+
+				century = (tm.tm_year >= 2000) ? 0x80 : 0;
+				tm.tm_year = tm.tm_year % 100;
+
+				BIN_TO_BCD(tm.tm_year);
+				BIN_TO_BCD(tm.tm_mday);
+				BIN_TO_BCD(tm.tm_hour);
+				BIN_TO_BCD(tm.tm_min);
+				BIN_TO_BCD(tm.tm_sec);
+				tm.tm_mon |= century;
+				
+				rtc_write(RTC_YEAR, tm.tm_year);
+				rtc_write(RTC_MONTH, tm.tm_mon);
+				rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
+				rtc_write(RTC_HOURS, tm.tm_hour);
+				rtc_write(RTC_MINUTES, tm.tm_min);
+				rtc_write(RTC_SECONDS, tm.tm_sec);
+
+				return 0;
+			}
+			break;
+		default:
+				return -ENOTTY;
+	}
+
+	return 0;
+}
+
+int 
+pcf8563_open(struct inode *inode, struct file *filp)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+int
+pcf8563_release(struct inode *inode, struct file *filp)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+EXPORT_NO_SYMBOLS;
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
diff -urN linux-2.4.20-pre2/arch/cris/drivers/serial.c linux-2.4.20-pre3/arch/cris/drivers/serial.c
--- linux-2.4.20-pre2/arch/cris/drivers/serial.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/drivers/serial.c	Sat Aug 17 14:18:40 2002
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.32 2002/05/22 13:58:00 johana Exp $
+/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,24 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.37  2002/08/13 13:02:37  bjornw
+ * Removed some warnings because of unused code
+ *
+ * Revision 1.36  2002/08/08 12:50:01  starvik
+ * Serial interrupt is shared with synchronous serial port driver
+ *
+ * Revision 1.35  2002/06/03 10:40:49  starvik
+ * Increased RS-485 RTS toggle timer to 2 characters
+ *
+ * Revision 1.34  2002/05/28 18:59:36  johana
+ * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
+ *
+ * Revision 1.33  2002/05/28 17:55:43  johana
+ * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
+ * timer from tranismit_chars (interrupt context).
+ * The timer toggles RTS in interrupt context when expired giving minimum
+ * latencies.
+ *
  * Revision 1.32  2002/05/22 13:58:00  johana
  * Renamed rs_write() to raw_write() and made it inline.
  * New rs_write() handles RS-485 if configured and enabled
@@ -303,7 +321,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.32 $";
+static char *serial_version = "$Revision: 1.37 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -342,7 +360,16 @@
 #include <linux/serial.h>
 /* while we keep our own stuff (struct e100_serial) in a local .h file */
 #include "serial.h"
+#include <asm/fasttimer.h>
 
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+#error "Disable SERIAL_FLUSH_DMA_FAST to use SERIAL_FAST_TIMER"
+#endif
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
 /*
  * All of the compatibilty code so we can compile serial.c against
  * older kernels is hidden in serial_compat.h
@@ -404,8 +431,10 @@
                     const unsigned char *buf, int count);
 static inline int raw_write(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
 static int e100_write_rs485(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
+#endif
 static int 
 get_lsr_info(struct e100_serial * info, unsigned int *value);
 
@@ -519,6 +548,9 @@
 static struct tty_struct *serial_table[NR_PORTS]; 
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
 
 #ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
 #define PROCSTAT(x) x
@@ -538,7 +570,7 @@
 
 static struct ser_statistics_type ser_stat[NR_PORTS];
 
-#else 
+#else
 
 #define PROCSTAT(x)
 
@@ -546,6 +578,9 @@
 
 /* RS-485 */
 #if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
 #if defined(CONFIG_ETRAX_RS485_ON_PA)
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
@@ -578,7 +613,7 @@
 	volatile unsigned char *port;
 	volatile unsigned char *shadow;
 	volatile unsigned char *dir_shadow;
-	
+
 	unsigned char dtr_bit;
 	unsigned char ri_bit;
 	unsigned char dsr_bit;
@@ -872,11 +907,6 @@
 		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
 		restore_flags(flags);
 	}
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].ri_bit, !set);
-#endif
 #endif
 }
 static inline void 
@@ -895,11 +925,6 @@
 		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
 		restore_flags(flags);
 	}
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].cd_bit, !set);
-#endif
 #endif
 }
 
@@ -1014,7 +1039,7 @@
 }
 
 static int
-e100_write_rs485(struct tty_struct *tty, int from_user, 
+e100_write_rs485(struct tty_struct *tty, int from_user,
                  const unsigned char *buf, int count)
 {
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
@@ -1031,7 +1056,22 @@
 	info->rs485.enabled = old_enabled;
 	return count;
 }
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+	struct e100_serial *info = (struct e100_serial *)data;
+
+	fast_timers_rs485[info->line].function = NULL;
+	e100_rts(info, info->rs485.rts_after_sent);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+	e100_enable_rx(info);
+	e100_enable_rxdma_irq(info);
+#endif
+}
 #endif
+#endif /* CONFIG_ETRAX_RS485 */
 
 /*
  * ------------------------------------------------------------
@@ -1174,6 +1214,16 @@
 		/* our job here is done, don't schedule any new DMA transfer */
 		info->tr_running = 0;
 
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+		if (info->rs485.enabled) {
+			/* Set a short timer to toggle RTS */
+			start_one_shot_timer(&fast_timers_rs485[info->line],
+			                     rs485_toggle_rts_timer_function,
+			                     (unsigned long)info,
+			                     info->char_time_usec*2,
+			                     "RS-485");
+		}
+#endif /* RS485 */
 		return;
 	}
 
@@ -1189,7 +1239,7 @@
 	*info->ocmdadr = 1;       /* dma command start -> R_DMAx_CMD */
 	
 	/* DMA is now running (hopefully) */
-}
+} /* transmit_chars */
 
 static void 
 start_transmit(struct e100_serial *info)
@@ -1205,7 +1255,7 @@
 	info->tr_running = 1;
 
 	transmit_chars(info);
-}
+} /* start_transmit */
 
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static int serial_fast_timer_started = 0;
@@ -1461,7 +1511,7 @@
 #endif
 
 	/* reset the input dma channel to be sure it works */
-	
+
 	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
 	while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
 	       IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
@@ -1636,7 +1686,7 @@
 	cli();
 
 	length = tty->flip.count;
-	
+
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
 		unsigned int count = buffer->length;
 
@@ -1889,7 +1939,7 @@
 			}
 			info->break_detected_cnt = 0;
 			DEBUG_LOG(info->line, "#iERR s d %04X\n",
-				  ((rstat & SER_ERROR_MASK) << 8) | data);
+			          ((rstat & SER_ERROR_MASK) << 8) | data);
 		}
 		PROCSTAT(ser_stat[info->line].early_errors_cnt++);
 	} else { /* It was a valid byte, now let the DMA do the rest */
@@ -1903,8 +1953,8 @@
 			 * previous interrupt we should discard it.
 			 */
 			long elapsed_usec = 
-				(curr_time - info->last_rx_active) * (1000000/HZ) + 
-				curr_time_u - info->last_rx_active_usec;
+			  (curr_time - info->last_rx_active) * (1000000/HZ) + 
+			  curr_time_u - info->last_rx_active_usec;
 			if (elapsed_usec < 2*info->char_time_usec) {
 				DEBUG_LOG(info->line, "FBRK %i\n", info->line);
 				/* Report as BREAK (error) and let
@@ -1942,7 +1992,7 @@
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
 
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 
 		/* Which line caused the irq? */
@@ -1992,28 +2042,6 @@
 	}
 }
 
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- * 	serial interrupt routine -> (scheduler tqueue) ->
- * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
- * 
- */
-static void 
-do_serial_hangup(void *private_)
-{
-	struct e100_serial	*info = (struct e100_serial *) private_;
-	struct tty_struct	*tty;
-
-	tty = info->tty;
-	if (!tty)
-		return;
-	
-	tty_hangup(tty);
-}
-
 static int 
 startup(struct e100_serial * info)
 {
@@ -2025,7 +2053,8 @@
 	if (!xmit_page)
 		return -ENOMEM;
 
-	save_flags(flags); cli();
+	save_flags(flags); 
+	cli();
 
 	/* if it was already initialized, skip this */
 
@@ -2322,7 +2351,7 @@
 
 static inline int 
 raw_write(struct tty_struct * tty, int from_user,
-	 const unsigned char *buf, int count)
+	  const unsigned char *buf, int count)
 {
 	int	c, ret = 0;
 	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
@@ -2435,6 +2464,11 @@
 		/* If we are in RS-485 mode, we need to toggle RTS and disable
 		 * the receiver before initiating a DMA transfer
 		 */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+		/* Abort any started timer */
+		fast_timers_rs485[info->line].function = NULL;
+		del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
 		e100_rts(info, info->rs485.rts_on_send);
 #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
 		e100_disable_rx(info);
@@ -2482,7 +2516,7 @@
 #endif /* CONFIG_ETRAX_RS485 */
 
 	return count;
-}
+} /* rs_write */
 
 
 /* how much space is available in the xmit buffer? */
@@ -2563,16 +2597,16 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
-	
+
 	if (I_IXOFF(tty))
 		info->x_char = STOP_CHAR(tty);
-	
+
 	/* Turn off RTS line (do this atomic) should here be an else ?? */
-	
+
 	save_flags(flags); 
 	cli();
 	e100_rts(info, 0);
@@ -2586,20 +2620,20 @@
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
 		else
 			info->x_char = START_CHAR(tty);
 	}
-	
+
 	/* Assert RTS line (do this atomic) */
-	
+
 	save_flags(flags); 
 	cli();
 	e100_rts(info, 1);
@@ -2722,8 +2756,8 @@
 #ifdef SERIAL_DEBUG_IO 
 struct state_str
 {
-  int state;
-  const char *str;
+	int state;
+	const char *str;
 };
 
 const struct state_str control_state_str[] = {
@@ -3678,6 +3712,15 @@
 			       serial_driver.name, info->line, (unsigned int)info->port);
 		}
 	}
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+	memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+	memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+	fast_timer_init();
+#endif
 
 #ifndef CONFIG_SVINTO_SIM
 	/* Not needed in simulator.  May only complicate stuff. */
@@ -3689,7 +3732,7 @@
 		panic("irq23");
 #endif
 #ifdef SERIAL_HANDLE_EARLY_ERRORS
-	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
+	if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
 		panic("irq8");
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT1
diff -urN linux-2.4.20-pre2/arch/cris/drivers/sync_serial.c linux-2.4.20-pre3/arch/cris/drivers/sync_serial.c
--- linux-2.4.20-pre2/arch/cris/drivers/sync_serial.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/drivers/sync_serial.c	Sat Aug 17 14:18:40 2002
@@ -227,7 +227,7 @@
 #else
 	ports[0].use_dma = 0;
 	initialize_port(0);
-	if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0]))
+	if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
@@ -258,9 +258,9 @@
 #else
 	ports[1].use_dma = 0;	
 	initialize_port(1);
-	if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
+	if (ports[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
 	{
-		if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1]))
+		if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
diff -urN linux-2.4.20-pre2/arch/cris/drivers/virtex.c linux-2.4.20-pre3/arch/cris/drivers/virtex.c
--- linux-2.4.20-pre2/arch/cris/drivers/virtex.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/arch/cris/drivers/virtex.c	Sat Aug 17 14:18:40 2002
@@ -0,0 +1,405 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : vertex.c
+*!
+*! DESCRIPTION: Implements an interface towards virtex FPGA (mounted on one of our
+*!              evaluation boards) from userspace using ioctl()'s
+*!
+*!              The FPGA can be programmed by copying the bit-file to /dev/fpga.
+*!
+*!                cp fpga.bit > /dev/fpga
+*!
+*!                Kernel log should look like:
+*!                  69900 bytes written
+*!                  FPGA-configuration completed, no errors
+*!
+*!              Number of bytes written depends on the FPGA
+*!
+*!                From Xilinx data sheet:
+*!                XCV50    559,200 bits
+*!                XCV100   781,216 bits
+*!                XCV800 4,715,616 bits
+*!
+*!              Accepted file type is the design.bit generated by Alliance
+*!              Design Manager.
+*!              This software just sends the bitfile into the device without
+*!              checking device type etc.
+*!
+*!              Sync-header 0xff 0xff 0xff 0xff defines the start for the
+*!              byte stream, everything from that position is written to the FPGA.
+*!
+*!  
+*! Jul 19 2002  Stefan Lundberg    Initial version.
+*! $Log: virtex.c,v $
+*! Revision 1.1  2002/06/25 09:58:58  stefanl
+*! New FPGA driver for Platoon
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: virtex.c,v 1.1 2002/06/25 09:58:58 stefanl Exp $ */
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <linux/hdreg.h>
+#include <linux/mm.h>
+
+#include <asm/etraxvirtex.h>
+
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "virtex.h"
+
+/******************* VIRTEX DEFINITION SECTION **************************/
+
+#define VIRTEX_DEBUG(x)
+
+#define VIRTEX_MAJOR 246  /* EXPERIMENTAL */
+
+static const char virtex_name[] = "virtex";
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+
+//
+// Read register interface for FPGA programming:
+//
+//   FPGA_DONE is connected to S1CD_N G28
+//   FPGA_INIT_N is connected to S1IO_N G27
+//
+
+// Write register interface for FPGA programming:
+//
+//  Bit:       15         14      13    12      9   8   7   0
+//        ____________________________________________________
+//       | fpga_write | program | cclk | reserved | cs | data |
+//       |____________|_________|______|__________|____|______|
+//
+
+
+// csp0 = cs_fpga1 = FPGA programming interface
+// csr0 = cs_fpga2 = register interface towards FPGA construction
+
+static volatile short *port_csp0_word_addr;
+static volatile short *port_csr0_word_addr;
+
+static volatile unsigned char open_count;
+static volatile unsigned char bytes_written;
+static volatile unsigned long bytes_written_cnt;
+static volatile unsigned char sync_found;
+static volatile unsigned char sync_count;
+static volatile unsigned char sync_ff_count;
+
+#define WRITE_FPGA_PROG_REG(data) *port_csp0_word_addr=(data)
+#define SET_PROGRAM_BIT(data) (data)|(1<<14)
+
+#define SET_WRITE_BIT(data) (data)|(1<<15)
+#define CLR_WRITE_BIT(data) (data)&(~(1<<15))
+
+#define SET_CS_BIT(data) (data)|(1<<8)
+#define CLR_CS_BIT(data) (data)&(~(1<<8))
+
+#define SET_CCLK_BIT(data) (data)|(1<<13)
+#define CLR_CCLK_BIT(data) (data)&(~(1<<13))
+
+// Bit in read port G (always inputs)
+#define READ_INIT  (*R_PORT_G_DATA)&(1<<27)
+#define READ_DONE  (*R_PORT_G_DATA)&(1<<28)
+
+
+void start_virtex_program(void)
+{
+  unsigned short reg_data=0;
+
+  printk("Start writing to FPGA\n");
+  reg_data = SET_CS_BIT(reg_data); // FPGA unselected
+
+  reg_data = SET_PROGRAM_BIT(reg_data);
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  while(!READ_INIT); // Wait for init
+  
+  reg_data = SET_WRITE_BIT(reg_data);
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  reg_data = CLR_CS_BIT(reg_data); // FPGA selected, CS is active low
+  WRITE_FPGA_PROG_REG(reg_data);
+  return;
+}
+
+// According to datasheet, bytes should be reversed, it is unknown to me why.
+unsigned char bit_reverse(unsigned char data) 
+{
+  unsigned char in=data;
+  unsigned short out=0;
+  unsigned int i=0;
+
+  for(i=0;i<8;i++) {
+    if(in&0x1) {
+      out|=0x1;
+    }
+    in=in>>1;
+    out=out<<1;
+  }
+
+  return(out>>1);
+  
+}
+
+void virtex_program(char* ptr,size_t count)
+{
+  int c;
+  char *p;
+  unsigned char data;  
+  unsigned short reg_data=0;
+//  short tmp_cnt;
+  
+  c=count;
+  p=ptr;
+
+  if(!sync_found) {
+    c=count;
+    p=ptr;
+    while(c--) {
+      data=(unsigned char)*p++;
+      sync_count++;
+
+      if(sync_count>=256) {
+        printk("Sync not found, aborting\n");
+        return;
+      }
+
+      if(data==0xff) {
+        sync_ff_count++;
+      } else {
+        sync_ff_count=0;
+      }
+      if(sync_ff_count==4) {
+        sync_found=1;
+        VIRTEX_DEBUG(printk("Sync found at offset %d\n",sync_count));
+        p--;p--;p--;p--;
+        c++;c++;c++;c++;
+        break;
+      }
+    }
+  }
+
+  if(sync_found) {
+    if(bytes_written==0) {
+      start_virtex_program();
+    }
+    bytes_written=1;
+  
+    reg_data = SET_PROGRAM_BIT(reg_data);
+    reg_data = SET_WRITE_BIT(reg_data);
+    reg_data = CLR_CS_BIT(reg_data);
+  
+//    tmp_cnt=0;
+    
+    printk("*");
+    while(c--) {
+      data=(unsigned char)*p++;
+      data=bit_reverse(data);
+
+/* debug
+      tmp_cnt++;
+      if(tmp_cnt<=32 || c<=32 ) {
+        printk("0x%x ",data); 
+      }
+      if(tmp_cnt==32 || c==0 ) {
+        printk("\n"); 
+      }
+*/
+      bytes_written_cnt++;
+      reg_data = CLR_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+      reg_data = SET_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+      reg_data = CLR_CCLK_BIT(reg_data);
+      WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+  
+    }
+  }
+   
+  return;
+}
+
+void stop_virtex_program(void)
+{
+  unsigned short reg_data=0;
+
+  reg_data = SET_PROGRAM_BIT(reg_data);
+  reg_data = SET_WRITE_BIT(reg_data);
+  reg_data = CLR_CCLK_BIT(reg_data);
+
+  reg_data = SET_CS_BIT(reg_data); // release CS
+  WRITE_FPGA_PROG_REG(reg_data);
+
+  reg_data = CLR_WRITE_BIT(reg_data); // release write, important to do!
+  WRITE_FPGA_PROG_REG(reg_data);
+  printk("%d bytes written\n",bytes_written_cnt);
+  if(READ_DONE) {
+    printk("FPGA-configuration completed, no errors\n");
+  } else {
+    printk("Error, FPGA-configuration failed\n");
+  }
+  return;
+}
+
+static int
+virtex_open(struct inode *inode, struct file *filp)
+{
+  port_csp0_word_addr = port_csp0_addr;
+  if(open_count>=1) {
+    printk("FPGA Device busy, aborting\n");
+    return(-EBUSY);
+  }
+  open_count++;
+  bytes_written=0;
+  sync_found=0;
+  sync_count=0;
+  sync_ff_count=0;
+  bytes_written_cnt=0;
+  return(0);
+}
+
+static int
+virtex_release(struct inode *inode, struct file *filp)
+{
+  open_count--;
+  if(bytes_written!=0)stop_virtex_program();
+  return 0;
+}
+
+// FPGA programming interface
+
+static ssize_t virtex_write(struct file * file, const char * buf, 
+                                 size_t count, loff_t *ppos)
+{
+  char *ptr;
+  VIRTEX_DEBUG(printk("Write FPGA count %d\n", count));
+  
+  ptr=kmalloc(count, GFP_KERNEL);
+  if(!ptr) {
+    printk("FPGA device, kernel malloc failed (%d) bytes\n",count);
+    return -EFAULT;
+  }
+  if(copy_from_user(ptr, buf, count)) {
+    printk("copy_from_user failed\n");
+    return -EFAULT;
+  }
+  
+  virtex_program(ptr,count);
+  
+  kfree(ptr);
+  return count;
+}
+
+/* Main device API. ioctl's to write or read to/from registers.
+ */
+
+int virtex_writereg(unsigned short theReg, unsigned short theValue)
+{
+  port_csr0_word_addr[theReg]=theValue;
+  return(0);
+}
+
+unsigned short virtex_readreg(unsigned short theReg)
+{
+  return(port_csr0_word_addr[theReg]);
+}
+
+
+static int
+virtex_ioctl(struct inode *inode, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+  if(_IOC_TYPE(cmd) != ETRAXVIRTEX_FPGA_IOCTYPE) {
+    return -EINVAL;
+  }
+  
+  switch (_IOC_NR(cmd)) {
+    case VIRTEX_FPGA_WRITEREG:
+      /* write to an FPGA register */
+      VIRTEX_DEBUG(printk("virtex wr %d %d\n", 
+               VIRTEX_FPGA_ARGREG(arg),
+               VIRTEX_FPGA_ARGVALUE(arg)));
+      
+      return virtex_writereg(VIRTEX_FPGA_ARGREG(arg),
+                             VIRTEX_FPGA_ARGVALUE(arg));
+    case VIRTEX_FPGA_READREG:
+    {
+      unsigned char val;
+      /* read from an FPGA register */
+      VIRTEX_DEBUG(printk("virtex rd %d ", 
+              VIRTEX_FPGA_ARGREG(arg)));
+      val = virtex_readreg(VIRTEX_FPGA_ARGREG(arg));
+      VIRTEX_DEBUG(printk("= %d\n", val));
+      return val;
+    }					    
+    default:
+      return -EINVAL;
+    }
+
+return 0;
+}
+
+static struct file_operations virtex_fops = {
+	owner:    THIS_MODULE,
+	ioctl:    virtex_ioctl,
+	open:     virtex_open,
+        write:    virtex_write,
+	release:  virtex_release,
+};
+
+static int __init
+virtex_init(void)
+{
+  int res;
+  
+  /* register char device */
+  res = register_chrdev(VIRTEX_MAJOR, virtex_name, &virtex_fops);
+  if(res < 0) {
+          printk(KERN_ERR "virtex: couldn't get a major number.\n");
+          return res;
+  }
+  
+  port_csr0_word_addr = (volatile unsigned short *) 
+                        ioremap((unsigned long)(MEM_CSR0_START |
+                                                MEM_NON_CACHEABLE), 16);
+     
+// see ~/platoon/rel2/platoon/os/linux/arch/cris/mm/init.c
+//              port_csp0_addr = (volatile unsigned long *)
+//                 ioremap((unsigned long)(MEM_CSP0_START |
+//                                         MEM_NON_CACHEABLE), 16);
+  
+  open_count=0;
+  
+  printk("VIRTEX(TM) FPGA driver v1.0, (c) 2002 Axis Communications AB\n");
+  
+  return 0;
+}
+
+/* this makes sure that virtex_init is called during boot */
+
+module_init(virtex_init);
+
+/****************** END OF FILE virtex.c ********************************/
diff -urN linux-2.4.20-pre2/arch/cris/drivers/virtex.h linux-2.4.20-pre3/arch/cris/drivers/virtex.h
--- linux-2.4.20-pre2/arch/cris/drivers/virtex.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/arch/cris/drivers/virtex.h	Sat Aug 17 14:18:40 2002
@@ -0,0 +1,7 @@
+/* $Id: virtex.h,v 1.1 2002/06/25 09:58:58 stefanl Exp $ */
+
+int virtex_writereg(unsigned short theReg, unsigned short theValue);
+unsigned short virtex_readreg(unsigned short theReg);
+
+
+
diff -urN linux-2.4.20-pre2/arch/cris/kernel/Makefile linux-2.4.20-pre3/arch/cris/kernel/Makefile
--- linux-2.4.20-pre2/arch/cris/kernel/Makefile	Fri Nov  9 13:58:02 2001
+++ linux-2.4.20-pre3/arch/cris/kernel/Makefile	Sat Aug 17 14:18:40 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $
+# $Id: Makefile,v 1.10 2002/05/27 15:41:40 johana Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -25,6 +25,7 @@
 
 obj-$(CONFIG_MODULES)    += ksyms.o
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
 
 # This dependency isn't caught by mkdep.  See entry.S.
 entry.o: entryoffsets.s
diff -urN linux-2.4.20-pre2/arch/cris/kernel/fasttimer.c linux-2.4.20-pre3/arch/cris/kernel/fasttimer.c
--- linux-2.4.20-pre2/arch/cris/kernel/fasttimer.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/arch/cris/kernel/fasttimer.c	Sat Aug 17 14:18:40 2002
@@ -0,0 +1,974 @@
+/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+ * linux/arch/cris/kernel/fasttimer.c
+ *
+ * Fast timers for ETRAX100/ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ *
+ * $Log: fasttimer.c,v $
+ * Revision 1.4  2002/05/28 17:47:59  johana
+ * Added del_fast_timer()
+ *
+ * Revision 1.3  2002/05/28 16:16:07  johana
+ * Handle empty fast_timer_list
+ *
+ * Revision 1.2  2002/05/27 15:38:42  johana
+ * Made it compile without warnings on Linux 2.4.
+ * (includes, wait_queue, PROC_FS and snprintf)
+ *
+ * Revision 1.1  2002/05/27 15:32:25  johana
+ * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
+ *
+ * Revision 1.8  2001/11/27 13:50:40  pkj
+ * Disable interrupts while stopping the timer and while modifying the
+ * list of active timers in timer1_handler() as it may be interrupted
+ * by other interrupts (e.g., the serial interrupt) which may add fast
+ * timers.
+ *
+ * Revision 1.7  2001/11/22 11:50:32  pkj
+ * * Only store information about the last 16 timers.
+ * * proc_fasttimer_read() now uses an allocated buffer, since it
+ *   requires more space than just a page even for only writing the
+ *   last 16 timers. The buffer is only allocated on request, so
+ *   unless /proc/fasttimer is read, it is never allocated.
+ * * Renamed fast_timer_started to fast_timers_started to match
+ *   fast_timers_added and fast_timers_expired.
+ * * Some clean-up.
+ *
+ * Revision 1.6  2000/12/13 14:02:08  johana
+ * Removed volatile for fast_timer_list
+ *
+ * Revision 1.5  2000/12/13 13:55:35  johana
+ * Added DEBUG_LOG, added som cli() and cleanup
+ *
+ * Revision 1.4  2000/12/05 13:48:50  johana
+ * Added range check when writing proc file, modified timer int handling
+ *
+ * Revision 1.3  2000/11/23 10:10:20  johana
+ * More debug/logging possibilities.
+ * Moved GET_JIFFIES_USEC() to timex.h and time.c
+ *
+ * Revision 1.2  2000/11/01 13:41:04  johana
+ * Clean up and bugfixes.
+ * Created new do_gettimeofday_fast() that gets a timeval struct
+ * with time based on jiffies and *R_TIMER0_DATA, uses a table
+ * for fast conversion of timer value to microseconds.
+ * (Much faster the standard do_gettimeofday() and we don't really
+ * wan't to use the true time - we wan't the "uptime" so timers don't screw up
+ * when we change the time.
+ * TODO: Add efficient support for continuous timers as well.
+ *
+ * Revision 1.1  2000/10/26 15:49:16  johana
+ * Added fasttimer, highresolution timers.
+ *
+ * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/svinto.h>
+#include <asm/fasttimer.h>
+#include <linux/proc_fs.h>
+
+
+#define DEBUG_LOG_INCLUDED
+#define FAST_TIMER_LOG
+//#define FAST_TIMER_TEST
+
+#define FAST_TIMER_SANITY_CHECKS
+
+#ifdef FAST_TIMER_SANITY_CHECKS
+#define SANITYCHECK(x) x
+static int sanity_failed = 0;
+#else
+#define SANITYCHECK(x)
+#endif
+
+#define D1(x)
+#define D2(x)
+#define DP(x)
+
+#define __INLINE__ inline
+
+static int fast_timer_running = 0;
+static int fast_timers_added = 0;
+static int fast_timers_started = 0;
+static int fast_timers_expired = 0;
+static int fast_timers_deleted = 0;
+static int fast_timer_is_init = 0;
+static int fast_timer_ints = 0;
+
+static struct fast_timer *fast_timer_list = NULL;
+
+#ifdef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG_MAX 128
+static const char * debug_log_string[DEBUG_LOG_MAX];
+static unsigned long debug_log_value[DEBUG_LOG_MAX];
+static int debug_log_cnt = 0;
+static int debug_log_cnt_wrapped = 0;
+
+#define DEBUG_LOG(string, value) \
+{ \
+  unsigned long log_flags; \
+  save_flags(log_flags); \
+  cli(); \
+  debug_log_string[debug_log_cnt] = (string); \
+  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
+  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
+  { \
+    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
+    debug_log_cnt_wrapped = 1; \
+  } \
+  restore_flags(log_flags); \
+}
+#else
+#define DEBUG_LOG(string, value)
+#endif
+
+
+/* The frequencies for index = clkselx number in R_TIMER_CTRL */
+#define NUM_TIMER_FREQ 15
+#define MAX_USABLE_TIMER_FREQ 7
+#define MAX_DELAY_US  853333L
+const unsigned long timer_freq_100[NUM_TIMER_FREQ] =
+{
+  3,   /* 0 3333 - 853333 us */
+  6,   /* 1 1666 - 426666 us */
+  12,  /* 2  833 - 213333 us */
+  24,  /* 3  416 - 106666 us */
+  48,  /* 4  208 -  53333 us */
+  96,  /* 5  104 -  26666 us */
+  192, /* 6   52 -  13333 us */
+  384, /* 7   26 -   6666 us */
+  576,
+  1152,
+  2304,
+  4608,
+  9216,
+  18432,
+  62500,
+  /* 15 = cascade */
+};
+#define NUM_TIMER_STATS 16
+#ifdef FAST_TIMER_LOG
+struct fast_timer timer_added_log[NUM_TIMER_STATS];
+struct fast_timer timer_started_log[NUM_TIMER_STATS];
+struct fast_timer timer_expired_log[NUM_TIMER_STATS];
+#endif
+
+int timer_div_settings[NUM_TIMER_STATS];
+int timer_freq_settings[NUM_TIMER_STATS];
+int timer_delay_settings[NUM_TIMER_STATS];
+
+/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
+void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+{
+  unsigned long sec = jiffies;
+  unsigned long usec = GET_JIFFIES_USEC();
+
+  usec += (sec % HZ) * (1000000 / HZ);
+  sec = sec / HZ;
+
+  if (usec > 1000000)
+  {
+    usec -= 1000000;
+    sec++;
+  }
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+}
+
+int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+{
+  if (t0->tv_sec < t1->tv_sec)
+  {
+    return -1;
+  }
+  else if (t0->tv_sec > t1->tv_sec)
+  {
+    return 1;
+  }
+  if (t0->tv_usec < t1->tv_usec)
+  {
+    return -1;
+  }
+  else if (t0->tv_usec > t1->tv_usec)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+void __INLINE__ start_timer1(unsigned long delay_us)
+{
+  int freq_index = 0; /* This is the lowest resolution */
+  unsigned long upper_limit = MAX_DELAY_US;
+
+  unsigned long div;
+  /* Start/Restart the timer to the new shorter value */
+  /* t = 1/freq = 1/19200 = 53us
+   * T=div*t,  div = T/t = delay_us*freq/1000000
+   */
+#if 1 /* Adaptive timer settings */
+  while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ)
+  {
+    freq_index++;
+    upper_limit >>= 1; /* Divide by 2 using shift */
+  }
+  if (freq_index > 0)
+  {
+    freq_index--;
+  }
+#else
+  freq_index = 6;
+#endif
+  div = delay_us * timer_freq_100[freq_index]/10000;
+  if (div < 2)
+  {
+    /* Maybe increase timer freq? */
+    div = 2;
+  }
+  if (div > 255)
+  {
+    div = 0; /* This means 256, the max the timer takes */
+    /* If a longer timeout than the timer can handle is used,
+     * then we must restart it when it goes off.
+     */
+  }
+
+  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div;
+  timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index;
+  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
+
+  D1(printk("start_timer1 : %d us freq: %i div: %i\n",
+            delay_us, freq_index, div));
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* Set timer values */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow &
+     ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
+     ~IO_MASK(R_TIMER_CTRL, tm1) &
+     ~IO_MASK(R_TIMER_CTRL, clksel1)) |
+    IO_FIELD(R_TIMER_CTRL, timerdiv1, div) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+    IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow |
+    IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  /* Start timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, run);
+
+  /* Enable timer1 irq */
+  *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
+  fast_timers_started++;
+  fast_timer_running = 1;
+}
+
+/* In version 1.4 this function takes 27 - 50 us */
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name)
+{
+  unsigned long flags;
+  struct fast_timer *tmp;
+
+  D1(printk("sft %s %d us\n", name, delay_us));
+
+  save_flags(flags);
+  cli();
+
+  do_gettimeofday_fast(&t->tv_set);
+  tmp = fast_timer_list;
+
+  SANITYCHECK({ /* Check so this is not in the list already... */
+    while (tmp != NULL)
+    {
+      if (tmp == t)
+      {
+        printk("timer name: %s data: 0x%08lX already in list!\n", name, data);
+        sanity_failed++;
+        return;
+      }
+      else
+      {
+        tmp = tmp->next;
+      }
+    }
+    tmp = fast_timer_list;
+  });
+
+  t->delay_us = delay_us;
+  t->function = function;
+  t->data = data;
+  t->name = name;
+
+  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
+  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
+  if (t->tv_expires.tv_usec > 1000000)
+  {
+    t->tv_expires.tv_usec -= 1000000;
+    t->tv_expires.tv_sec++;
+  }
+#ifdef FAST_TIMER_LOG
+  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
+#endif
+  fast_timers_added++;
+
+  /* Check if this should timeout before anything else */
+  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+  {
+    /* Put first in list and modify the timer value */
+    t->prev = NULL;
+    t->next = fast_timer_list;
+    if (fast_timer_list)
+    {
+      fast_timer_list->prev = t;
+    }
+    fast_timer_list = t;
+#ifdef FAST_TIMER_LOG
+    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+    start_timer1(delay_us);
+  } else {
+    /* Put in correct place in list */
+    while (tmp->next &&
+           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+    {
+      tmp = tmp->next;
+    }
+    /* Insert t after tmp */
+    t->prev = tmp;
+    t->next = tmp->next;
+    if (tmp->next)
+    {
+      tmp->next->prev = t;
+    }
+    tmp->next = t;
+  }
+
+  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+
+  restore_flags(flags);
+} /* start_one_shot_timer */
+
+static inline int fast_timer_pending (const struct fast_timer * t)
+{
+  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
+}
+
+static inline int detach_fast_timer (struct fast_timer *t)
+{
+  struct fast_timer *next, *prev;
+  if (!fast_timer_pending(t))
+    return 0;
+  next = t->next;
+  prev = t->prev;
+  if (next)
+    next->prev = prev;
+  if (prev)
+    prev->next = next;
+  else
+    fast_timer_list = next;
+  fast_timers_deleted++;
+  return 1;
+}
+
+int del_fast_timer(struct fast_timer * t)
+{
+  unsigned long flags;
+  int ret;
+  
+  save_flags(flags);
+  cli();
+  ret = detach_fast_timer(t);
+  t->next = t->prev = NULL;
+  restore_flags(flags);
+  return ret;
+} /* del_fast_timer */
+
+
+/* Interrupt routines or functions called in interrupt context */
+
+/* Timer 1 interrupt handler */
+
+static void
+timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct fast_timer *t;
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  /* Clear timer1 irq */
+  *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
+
+  /* First stop timer, then ack interrupt */
+  /* Stop timer */
+  *R_TIMER_CTRL = r_timer_ctrl_shadow =
+    (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+    IO_STATE(R_TIMER_CTRL, tm1, stop_ld);
+
+  /* Ack interrupt */
+  *R_TIMER_CTRL =  r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr);
+
+  fast_timer_running = 0;
+  fast_timer_ints++;
+
+  restore_flags(flags);
+
+  t = fast_timer_list;
+  while (t)
+  {
+    struct timeval tv;
+
+    /* Has it really expired? */
+    do_gettimeofday_fast(&tv);
+    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+
+    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+    {
+      /* Yes it has expired */
+#ifdef FAST_TIMER_LOG
+      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
+#endif
+      fast_timers_expired++;
+
+      /* Remove this timer before call, since it may reuse the timer */
+      save_flags(flags);
+      cli();
+      if (t->prev)
+      {
+        t->prev->next = t->next;
+      }
+      else
+      {
+        fast_timer_list = t->next;
+      }
+      if (t->next)
+      {
+        t->next->prev = t->prev;
+      }
+      t->prev = NULL;
+      t->next = NULL;
+      restore_flags(flags);
+
+      if (t->function != NULL)
+      {
+        t->function(t->data);
+      }
+      else
+      {
+        DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints);
+      }
+    }
+    else
+    {
+      /* Timer is to early, let's set it again using the normal routines */
+      D1(printk(".\n"));
+    }
+
+    save_flags(flags);
+    cli();
+    if ((t = fast_timer_list) != NULL)
+    {
+      /* Start next timer.. */
+      long us;
+      struct timeval tv;
+
+      do_gettimeofday_fast(&tv);
+      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
+            t->tv_expires.tv_usec - tv.tv_usec);
+      if (us > 0)
+      {
+        if (!fast_timer_running)
+        {
+#ifdef FAST_TIMER_LOG
+          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+          start_timer1(us);
+        }
+        restore_flags(flags);
+        break;
+      }
+      else
+      {
+        /* Timer already expired, let's handle it better late than never.
+         * The normal loop handles it
+         */
+        D1(printk("e! %d\n", us));
+      }
+    }
+    restore_flags(flags);
+  }
+
+  if (!t)
+  {
+    D1(printk("t1 stop!\n"));
+  }
+}
+
+static void wake_up_func(unsigned long data)
+{
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
+#else
+  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
+#endif
+  wake_up(sleep_wait_p);
+}
+
+
+/* Useful API */
+
+void schedule_usleep(unsigned long us)
+{
+  struct fast_timer t;
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t sleep_wait;
+  DECLARE_WAITQUEUE(wait, current);
+#else
+  struct wait_queue *sleep_wait = NULL;
+  struct wait_queue wait = { current, NULL };
+#endif
+
+  D1(printk("schedule_usleep(%d)\n", us));
+  add_wait_queue(&sleep_wait, &wait);
+  set_current_state(TASK_INTERRUPTIBLE);
+  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
+                       "usleep");
+  schedule();
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&sleep_wait, &wait);
+  D1(printk("done schedule_usleep(%d)\n", us));
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               );
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static struct proc_dir_entry *fasttimer_proc_entry;
+#else
+static struct proc_dir_entry fasttimer_proc_entry =
+{
+  0, 9, "fasttimer",
+  S_IFREG | S_IRUGO, 1, 0, 0,
+  0, NULL /* ops -- default to array */,
+  &proc_fasttimer_read /* get_info */,
+};
+#endif
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_PROC_FS
+
+/* This value is very much based on testing */
+#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
+
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               )
+{
+  unsigned long flags;
+  int i = 0;
+  int num_to_show;
+  struct timeval tv;
+  struct fast_timer *t, *nextt;
+  static char *bigbuf = NULL;
+  static unsigned long used;
+
+  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
+  {
+    used = 0;
+    bigbuf[0] = '\0';
+    return 0;
+  }
+
+  if (!offset || !used)
+  {
+    do_gettimeofday_fast(&tv);
+
+    used = 0;
+    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
+                    fast_timers_added);
+    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
+                    fast_timers_started);
+    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
+                    fast_timer_ints);
+    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
+                    fast_timers_expired);
+    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
+                    fast_timers_deleted);
+    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
+                    fast_timer_running ? "yes" : "no");
+    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
+                    (unsigned long)tv.tv_sec,
+                    (unsigned long)tv.tv_usec);
+#ifdef FAST_TIMER_SANITY_CHECKS
+    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
+                    sanity_failed);
+#endif
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef DEBUG_LOG_INCLUDED
+    {
+      int end_i = debug_log_cnt;
+      i = 0;
+
+      if (debug_log_cnt_wrapped)
+      {
+        i = debug_log_cnt;
+      }
+
+      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
+             used+100 < BIG_BUF_SIZE)
+      {
+        used += sprintf(bigbuf + used, debug_log_string[i],
+                        debug_log_value[i]);
+        i = (i+1) % DEBUG_LOG_MAX;
+      }
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
+    {
+      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+
+#if 1 //ndef FAST_TIMER_LOG
+      used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i"
+                      "\n",
+                      timer_div_settings[cur],
+                      timer_freq_settings[cur],
+                      timer_delay_settings[cur]
+                      );
+#endif
+#ifdef FAST_TIMER_LOG
+      t = &timer_started_log[cur];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+#endif
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef FAST_TIMER_LOG
+    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    used += sprintf(bigbuf + used, "Active timers:\n");
+    save_flags(flags);
+    cli();
+    t = fast_timer_list;
+    while (t != NULL && (used+100 < BIG_BUF_SIZE))
+    {
+      nextt = t->next;
+      restore_flags(flags);
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+/*                      " func: 0x%08lX" */
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+/*                      , t->function */
+                      );
+      cli();
+      if (t->next != nextt)
+      {
+        printk("timer removed!\n");
+      }
+      t = nextt;
+    }
+    restore_flags(flags);
+  }
+
+  if (used - offset < len)
+  {
+    len = used - offset;
+  }
+
+  memcpy(buf, bigbuf + offset, len);
+  *start = buf;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+  *eof = 1;
+#endif
+
+  return len;
+}
+#endif /* PROC_FS */
+
+#ifdef FAST_TIMER_TEST
+static volatile unsigned long i = 0;
+static volatile int num_test_timeout = 0;
+static struct fast_timer tr[10];
+static int exp_num[10];
+
+static struct timeval tv_exp[100];
+
+static void test_timeout(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+
+  num_test_timeout++;
+}
+
+static void test_timeout1(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+  if (data < 7)
+  {
+    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
+    i++;
+  }
+  num_test_timeout++;
+}
+
+DP(
+static char buf0[2000];
+static char buf1[2000];
+static char buf2[2000];
+static char buf3[2000];
+static char buf4[2000];
+);
+
+static char buf5[6000];
+static int j_u[1000];
+
+static void fast_timer_test(void)
+{
+  int prev_num;
+  int j;
+
+  struct timeval tv, tv0, tv1, tv2;
+
+  printk("fast_timer_test() start\n");
+  do_gettimeofday_fast(&tv);
+
+  for (j = 0; j < 1000; j++)
+  {
+    j_u[j] = GET_JIFFIES_USEC();
+  }
+  for (j = 0; j < 100; j++)
+  {
+    do_gettimeofday_fast(&tv_exp[j]);
+  }
+  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+
+  for (j = 0; j < 1000; j++)
+  {
+    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+    j += 4;
+  }
+  for (j = 0; j < 100; j++)
+  {
+    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
+           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
+           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
+           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
+           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+    j += 4;
+  }
+  do_gettimeofday_fast(&tv0);
+  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
+  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
+  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
+  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
+  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
+  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
+  i++;
+  do_gettimeofday_fast(&tv1);
+
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+
+  prev_num = num_test_timeout;
+  while (num_test_timeout < i)
+  {
+    if (num_test_timeout != prev_num)
+    {
+      prev_num = num_test_timeout;
+    }
+  }
+  do_gettimeofday_fast(&tv2);
+  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
+  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
+  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+  DP(printk("buf0:\n");
+     printk(buf0);
+     printk("buf1:\n");
+     printk(buf1);
+     printk("buf2:\n");
+     printk(buf2);
+     printk("buf3:\n");
+     printk(buf3);
+     printk("buf4:\n");
+     printk(buf4);
+  );
+  printk("buf5:\n");
+  printk(buf5);
+
+  printk("timers set:\n");
+  for(j = 0; j<i; j++)
+  {
+    struct fast_timer *t = &tr[j];
+    printk("%-10s set: %6is %06ius exp: %6is %06ius "
+           "data: 0x%08X func: 0x%08X\n",
+           t->name,
+           t->tv_set.tv_sec,
+           t->tv_set.tv_usec,
+           t->tv_expires.tv_sec,
+           t->tv_expires.tv_usec,
+           t->data,
+           t->function
+           );
+
+    printk("           del: %6ius     did exp: %6is %06ius as #%i error: %6li\n",
+           t->delay_us,
+           tv_exp[j].tv_sec,
+           tv_exp[j].tv_usec,
+           exp_num[j],
+           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+  }
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+  printk("buf5 after all done:\n");
+  printk(buf5);
+  printk("fast_timer_test() done\n");
+}
+#endif
+
+
+void fast_timer_init(void)
+{
+  /* For some reason, request_irq() hangs when called froom time_init() */
+  if (!fast_timer_is_init)
+  {
+#if 0 && defined(FAST_TIMER_TEST)
+    int i;
+#endif
+
+    printk("fast_timer_init()\n");
+
+#if 0 && defined(FAST_TIMER_TEST)
+    for (i = 0; i <= TIMER0_DIV; i++)
+    {
+      /* We must be careful not to get overflow... */
+      printk("%3i %6u\n", i, timer0_value_us[i]);
+    }
+#endif
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
+     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+#else
+    proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
+#endif
+#endif /* PROC_FS */
+    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ,
+                   "fast timer int", NULL))
+    {
+      printk("err: timer1 irq\n");
+    }
+    fast_timer_is_init = 1;
+#ifdef FAST_TIMER_TEST
+    printk("do test\n");
+    fast_timer_test();
+#endif
+  }
+}
diff -urN linux-2.4.20-pre2/arch/cris/kernel/kgdb.c linux-2.4.20-pre3/arch/cris/kernel/kgdb.c
--- linux-2.4.20-pre2/arch/cris/kernel/kgdb.c	Fri Nov  9 13:58:02 2001
+++ linux-2.4.20-pre3/arch/cris/kernel/kgdb.c	Sat Aug 17 14:18:40 2002
@@ -18,6 +18,9 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.7  2002/07/12 09:14:56  bjornw
+*! Corrected typo
+*!
 *! Revision 1.6  2001/10/09 13:10:03  matsfg
 *! Added $ on registers and removed some underscores
 *!
@@ -55,7 +58,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $
+*! $Id: kgdb.c,v 1.7 2002/07/12 09:14:56 bjornw Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -1064,7 +1067,7 @@
 					int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
 					int status;
 #ifdef PROCESS_SUPPORT
-					if (current_thread_g =! executing_task)
+					if (current_thread_g != executing_task)
 						status = write_stack_register (current_thread_g, regno, suffix+1);
 					else
 #endif
diff -urN linux-2.4.20-pre2/arch/cris/kernel/setup.c linux-2.4.20-pre3/arch/cris/kernel/setup.c
--- linux-2.4.20-pre2/arch/cris/kernel/setup.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.20-pre3/arch/cris/kernel/setup.c	Sat Aug 17 14:18:40 2002
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.24 2001/12/07 17:03:19 bjornw Exp $
+/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -169,20 +169,18 @@
 
 	*cmdline_p = command_line;
 
-	if (romfs_in_flash) {
-		strncpy(command_line, "root=", COMMAND_LINE_SIZE);
-		strncpy(command_line+5, CONFIG_ETRAX_ROOT_DEVICE,
+	strncpy(command_line, "root=", COMMAND_LINE_SIZE);
+	strncpy(command_line+5, CONFIG_ETRAX_ROOT_DEVICE,
 			COMMAND_LINE_SIZE-5);
 
-		/* Save command line copy for /proc/cmdline */
-
-		memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
-		saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-	}
+	/* Save command line copy for /proc/cmdline */
+	
+	memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
 	/* give credit for the CRIS port */
 
-	printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
+	printk("Linux/CRIS port on ETRAX 100LX (c) 2001, 2002 Axis Communications AB\n");
 
 }
 
diff -urN linux-2.4.20-pre2/arch/cris/lib/dram_init.S linux-2.4.20-pre3/arch/cris/lib/dram_init.S
--- linux-2.4.20-pre2/arch/cris/lib/dram_init.S	Mon Oct  8 11:43:54 2001
+++ linux-2.4.20-pre3/arch/cris/lib/dram_init.S	Sat Aug 17 14:18:40 2002
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.10 2001/10/04 12:00:21 martinnn Exp $
+/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,12 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.12  2002/08/09 11:37:37  orjanf
+ * Added double initialization work-around for Samsung SDRAMs.
+ *
+ * Revision 1.11  2002/06/04 11:43:21  starvik
+ * Check if mrs_data is specified in kernelconfig (necessary for MCM)
+ *
  * Revision 1.10  2001/10/04 12:00:21  martinnn
  * Added missing underscores.
  *
@@ -70,7 +76,11 @@
 
 	move.d   CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0
 	move.d   $r0, [R_DRAM_TIMING]
-#else	
+#else
+	;; Samsung SDRAMs seem to require to be initialized twice to work properly.
+	moveq    2, $r6	
+_sdram_init:
+	
 	; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
 	
 	; Bank configuration
@@ -82,6 +92,12 @@
 	; CAS latency = 3 && bus_width = 32 => 0x60
 	; CAS latency = 2 && bus_width = 16 => 0x20
 	; CAS latency = 3 && bus_width = 16 => 0x30
+
+	; Check if value is already supplied in kernel config
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2
+	and.d    0x00ff0000, $r2
+	bne	 _set_timing
+	lsrq     16, $r2
 	
 	move.d   0x40, $r2       ; Assume 32 bits and CAS latency = 2
 	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
@@ -142,6 +158,9 @@
 	bne      1b
 	nop
 	move.d   $r5, [R_SDRAM_TIMING]
+	subq     1, $r6
+	bne      _sdram_init
+	nop
 	ba       _sdram_commands_end
 	nop
 
diff -urN linux-2.4.20-pre2/arch/cris/lib/hw_settings.S linux-2.4.20-pre3/arch/cris/lib/hw_settings.S
--- linux-2.4.20-pre2/arch/cris/lib/hw_settings.S	Wed Jul  4 11:50:39 2001
+++ linux-2.4.20-pre3/arch/cris/lib/hw_settings.S	Sat Aug 17 14:18:40 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $
+ * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
@@ -16,8 +16,8 @@
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
 	
-	.ascii "HW_PARAM_MAGIC" ; Magic number
-	.dword 0xc0004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"					; Magic number
+	.dword CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -urN linux-2.4.20-pre2/arch/cris/mm/fault.c linux-2.4.20-pre3/arch/cris/mm/fault.c
--- linux-2.4.20-pre2/arch/cris/mm/fault.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/cris/mm/fault.c	Sat Aug 17 14:18:40 2002
@@ -6,6 +6,9 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.21  2002/05/28 14:24:56  bjornw
+ *  Corrected typo
+ *
  *  Revision 1.20  2001/11/22 13:34:06  bjornw
  *  * Bug workaround (LX TR89): force a rerun of the whole of an interrupted
  *    unaligned write, because the second half of the write will be corrupted
diff -urN linux-2.4.20-pre2/arch/i386/kernel/apic.c linux-2.4.20-pre3/arch/i386/kernel/apic.c
--- linux-2.4.20-pre2/arch/i386/kernel/apic.c	Sat Aug 17 14:18:07 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/apic.c	Sat Aug 17 14:18:40 2002
@@ -1130,7 +1130,7 @@
 	   6: Received illegal vector
 	   7: Illegal register address
 	*/
-	printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n",
+	printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n",
 	        smp_processor_id(), v , v1);
 }
 
diff -urN linux-2.4.20-pre2/arch/i386/kernel/dmi_scan.c linux-2.4.20-pre3/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20-pre2/arch/i386/kernel/dmi_scan.c	Sat Aug 17 14:18:07 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/dmi_scan.c	Sat Aug 17 14:18:40 2002
@@ -635,6 +635,12 @@
 			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
 			} },
 	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0209Z3"),
+			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
+			} },
+	
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204K2"),
diff -urN linux-2.4.20-pre2/arch/i386/kernel/pci-i386.c linux-2.4.20-pre3/arch/i386/kernel/pci-i386.c
--- linux-2.4.20-pre2/arch/i386/kernel/pci-i386.c	Sun Nov  4 09:31:58 2001
+++ linux-2.4.20-pre3/arch/i386/kernel/pci-i386.c	Sat Aug 17 14:18:40 2002
@@ -303,7 +303,7 @@
 	pcibios_assign_resources();
 }
 
-int pcibios_enable_resources(struct pci_dev *dev)
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -312,6 +312,10 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+			
 		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);
diff -urN linux-2.4.20-pre2/arch/i386/kernel/pci-i386.h linux-2.4.20-pre3/arch/i386/kernel/pci-i386.h
--- linux-2.4.20-pre2/arch/i386/kernel/pci-i386.h	Sun Nov 11 10:09:32 2001
+++ linux-2.4.20-pre3/arch/i386/kernel/pci-i386.h	Sat Aug 17 14:18:40 2002
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
+int pcibios_enable_resources(struct pci_dev *, int);
 
 /* pci-pc.c */
 
diff -urN linux-2.4.20-pre2/arch/i386/kernel/pci-pc.c linux-2.4.20-pre3/arch/i386/kernel/pci-pc.c
--- linux-2.4.20-pre2/arch/i386/kernel/pci-pc.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/pci-pc.c	Sat Aug 17 14:18:41 2002
@@ -1393,11 +1393,11 @@
 	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	int err;
 
-	if ((err = pcibios_enable_resources(dev)) < 0)
+	if ((err = pcibios_enable_resources(dev, mask)) < 0)
 		return err;
 	pcibios_enable_irq(dev);
 	return 0;
diff -urN linux-2.4.20-pre2/arch/i386/kernel/pci-visws.c linux-2.4.20-pre3/arch/i386/kernel/pci-visws.c
--- linux-2.4.20-pre2/arch/i386/kernel/pci-visws.c	Sun Nov  4 09:31:58 2001
+++ linux-2.4.20-pre3/arch/i386/kernel/pci-visws.c	Sat Aug 17 14:18:41 2002
@@ -131,9 +131,9 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-	return pcibios_enable_resources(dev);
+	return pcibios_enable_resources(dev, mask);
 }
 
 void __init pcibios_penalize_isa_irq(irq)
diff -urN linux-2.4.20-pre2/arch/i386/kernel/semaphore.c linux-2.4.20-pre3/arch/i386/kernel/semaphore.c
--- linux-2.4.20-pre2/arch/i386/kernel/semaphore.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/semaphore.c	Sat Aug 17 14:18:41 2002
@@ -262,31 +262,30 @@
  */
 #if defined(CONFIG_SMP)
 asm(
-"
-.align	4
-.globl	__write_lock_failed
-__write_lock_failed:
-	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax)
-1:	rep; nop
-	cmpl	$" RW_LOCK_BIAS_STR ",(%eax)
-	jne	1b
-
-	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax)
-	jnz	__write_lock_failed
-	ret
-
-
-.align	4
-.globl	__read_lock_failed
-__read_lock_failed:
-	lock ; incl	(%eax)
-1:	rep; nop
-	cmpl	$1,(%eax)
-	js	1b
+".text\n"
+".align	4\n"
+".globl	__write_lock_failed\n"
+"__write_lock_failed:\n\t"
+	LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax)\n"
+"1:	rep; nop\n\t"
+	"cmpl	$" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+	"jne	1b\n\t"
+	LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax)\n\t"
+	"jnz	__write_lock_failed\n\t"
+	"ret"
+);
 
-	lock ; decl	(%eax)
-	js	__read_lock_failed
-	ret
-"
+asm(
+".text\n"
+".align	4\n"
+".globl	__read_lock_failed\n"
+"__read_lock_failed:\n\t"
+	LOCK "incl	(%eax)\n"
+"1:	rep; nop\n\t"
+	"cmpl	$1,(%eax)\n\t"
+	"js	1b\n\t"
+	LOCK "decl	(%eax)\n\t"
+	"js	__read_lock_failed\n\t"
+	"ret"
 );
 #endif
diff -urN linux-2.4.20-pre2/arch/i386/kernel/setup.c linux-2.4.20-pre3/arch/i386/kernel/setup.c
--- linux-2.4.20-pre2/arch/i386/kernel/setup.c	Sat Aug 17 14:18:08 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/setup.c	Sat Aug 17 14:18:41 2002
@@ -71,13 +71,6 @@
  *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
  *  Dave Jones <davej@suse.de>, September, October 2001.
  *
- *  Short-term fix for a conflicting cache attribute bug in the kernel
- *  that is exposed by advanced speculative caching on new AMD Athlon
- *  processors.
- *  Richard Brunner <richard.brunner@amd.com> and Mark Langsdorf
- *  <mark.langsdorf@amd.com>, June 2002 
- *  Adapted to work with uniprocessor APIC by Bryan O'Sullivan
- *  <bos@serpentine.com>, June 2002.
  */
 
 /*
@@ -181,12 +174,6 @@
 
 int enable_acpi_smp_table;
 
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-int disable_adv_spec_cache __initdata = 1;
-#else
-int disable_adv_spec_cache __initdata = 0;
-#endif /* CONFIG_AGP */
-
 /*
  * This is set up by the setup-routine at boot-time
  */
@@ -745,41 +732,6 @@
 } /* setup_memory_region */
 
 
-int __init amd_adv_spec_cache_feature(void)
-{
-	char vendor_id[16];
-	int ident;
-	int family, model;
- 
-	/* Must have CPUID */
-	if(!have_cpuid_p())
-		goto donthave;
-	if(cpuid_eax(0)<1)
-		goto donthave;
-	
-	/* Must be x86 architecture */
-	cpuid(0, &ident,  
-		(int *)&vendor_id[0],
-		(int *)&vendor_id[8],
-		(int *)&vendor_id[4]);
-
-	if (memcmp(vendor_id, "AuthenticAMD", 12)) 
-	       goto donthave;
-
-	ident = cpuid_eax(1);
-	family = (ident >> 8) & 0xf;
-	model  = (ident >> 4) & 0xf;
-	if (((family == 6)  && (model >= 6)) || (family == 15)) {
-		printk(KERN_INFO "Advanced speculative caching feature present\n");
-		return 1;
-	}
-
-donthave:
-	printk(KERN_INFO "Advanced speculative caching feature not present\n");
-	return 0;
-}
-
-
 static void __init parse_cmdline_early (char ** cmdline_p)
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
@@ -845,17 +797,6 @@
 		 */
 		else if (!memcmp(from, "highmem=", 8))
 			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
-		/*
-		 * unsafe-gart-alias overrides the short-term fix for a
-		 * conflicting cache attribute bug in the kernel that is
-		 * exposed by advanced speculative caching in newer AMD
-		 * Athlon processors.  Overriding the fix will allow
-		 * higher performance but the kernel bug can cause system
-		 * lock-ups if the system uses an AGP card.  unsafe-gart-alias
-		 * can be turned on for higher performance in servers.
-		 */
-		else if (!memcmp(from, "unsafe-gart-alias", 17))
-			disable_adv_spec_cache = 0;
 nextchar:
 		c = *(from++);
 		if (!c)
@@ -1124,14 +1065,6 @@
 #ifdef CONFIG_SMP
 	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
 #endif
-	/*
-	 * short-term fix for a conflicting cache attribute bug in the 
-	 * kernel that is exposed by advanced speculative caching on
-	 * newer AMD Athlon processors.
-	 */
-	if (disable_adv_spec_cache && amd_adv_spec_cache_feature())
-		clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
-
 	paging_init();
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -1308,31 +1241,6 @@
 	       l2size, ecx & 0xFF);
 }
 
-
-/*=======================================================================
- * amd_adv_spec_cache_disable
- * Setting a special MSR big that disables a small part of advanced
- * speculative caching as part of a short-term fix for a conflicting cache
- * attribute bug in the kernel that is exposed by advanced speculative
- * caching in newer AMD Athlon processors.
- =======================================================================*/
-static void amd_adv_spec_cache_disable(void)
-{
-	printk(KERN_INFO "Disabling advanced speculative caching\n");
-
-	__asm__ __volatile__ (
-		" movl	 $0x9c5a203a,%%edi   \n" /* msr enable */
-		" movl	 $0xc0011022,%%ecx   \n" /* msr addr	 */
-		" rdmsr			     \n" /* get reg val	 */
-		" orl	 $0x00010000,%%eax   \n" /* set bit 16	 */
-		" wrmsr			     \n" /* put it back	 */
-		" xorl	%%edi, %%edi	     \n" /* clear msr enable */
-		: /* no outputs */
-		: /* no inputs, either */
-		: "%eax","%ecx","%edx","%edi" /* clobbered regs */ );
-}
-
-
 /*
  *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  *	misexecution of code under Linux. Owners of such processors should
@@ -1466,21 +1374,10 @@
  			 * to enable SSE on Palomino/Morgan CPU's.
 			 * If the BIOS didn't enable it already, enable it
 			 * here.
-			 *
-			 * Avoiding the use of 4MB/2MB pages along with
-			 * setting a special MSR bit that disables a small
-			 * part of advanced speculative caching as part of a
-			 * short-term fix for a conflicting cache attribute
-			 * bug in the kernel that is exposed by advanced
-			 * speculative caching in newer AMD Atlon processors.
-			 *
-			 * If we cleared the PSE bit earlier as part
-			 * of the workaround for this problem, we need
-			 * to clear it again, as our caller may have
-			 * clobbered it if uniprocessor APIC is enabled.
 			 */
-			if (c->x86_model >= 6) {
-				if (!cpu_has_xmm) {
+			if (c->x86_model == 6 || c->x86_model == 7) {
+				if (!test_bit(X86_FEATURE_XMM,
+					      &c->x86_capability)) {
 					printk(KERN_INFO
 					       "Enabling Disabled K7/SSE Support...\n");
 					rdmsr(MSR_K7_HWCR, l, h);
@@ -1489,18 +1386,6 @@
 					set_bit(X86_FEATURE_XMM,
                                                 &c->x86_capability);
 				}
-				if (disable_adv_spec_cache &&
-				    amd_adv_spec_cache_feature()) {
-					clear_bit(X86_FEATURE_PSE,
-						  &c->x86_capability);
-					amd_adv_spec_cache_disable();
-				}
-			}
-			break;
-		case 15: 
-			if (disable_adv_spec_cache && amd_adv_spec_cache_feature()) {
-				clear_bit(X86_FEATURE_PSE, &c->x86_capability);
-				amd_adv_spec_cache_disable();
 			}
 			break;
 
@@ -2750,12 +2635,6 @@
 			      &c->x86_capability[0]);
 			c->x86 = (tfms >> 8) & 15;
 			c->x86_model = (tfms >> 4) & 15;
-			if ( (c->x86_vendor == X86_VENDOR_AMD) &&
-				(c->x86 == 0xf)) {
-				/* AMD Extended Family and Model Values */
-				c->x86 += (tfms >> 20) & 0xff;
-				c->x86_model += (tfms >> 12) & 0xf0;
-			}
 			c->x86_mask = tfms & 15;
 		} else {
 			/* Have CPUID level 0 only - unheard of */
diff -urN linux-2.4.20-pre2/arch/i386/kernel/trampoline.S linux-2.4.20-pre3/arch/i386/kernel/trampoline.S
--- linux-2.4.20-pre2/arch/i386/kernel/trampoline.S	Thu Oct  4 18:42:54 2001
+++ linux-2.4.20-pre3/arch/i386/kernel/trampoline.S	Sat Aug 17 14:18:41 2002
@@ -36,9 +36,7 @@
 
 ENTRY(trampoline_data)
 r_base = .
-#ifdef CONFIG_MULTIQUAD
-	wbinvd
-#endif /* CONFIG_MULTIQUAD */
+	wbinvd			# Needed for NUMA-Q should be harmless for others
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
diff -urN linux-2.4.20-pre2/arch/i386/kernel/traps.c linux-2.4.20-pre3/arch/i386/kernel/traps.c
--- linux-2.4.20-pre2/arch/i386/kernel/traps.c	Sat Aug 17 14:18:08 2002
+++ linux-2.4.20-pre3/arch/i386/kernel/traps.c	Sat Aug 17 14:18:41 2002
@@ -313,8 +313,13 @@
 static void inline do_trap(int trapnr, int signr, char *str, int vm86,
 			   struct pt_regs * regs, long error_code, siginfo_t *info)
 {
-	if (vm86 && regs->eflags & VM_MASK)
-		goto vm86_trap;
+	if (regs->eflags & VM_MASK) {
+		if (vm86)
+			goto vm86_trap;
+		else
+			goto trap_signal;
+	}
+
 	if (!(regs->xcs & 3))
 		goto kernel_trap;
 
@@ -522,10 +527,15 @@
 {
 	unsigned int condition;
 	struct task_struct *tsk = current;
+	unsigned long eip = regs->eip;
 	siginfo_t info;
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
+	/* If the user set TF, it's simplest to clear it right away. */
+	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
+		goto clear_TF;
+
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7])
diff -urN linux-2.4.20-pre2/arch/i386/mm/Makefile linux-2.4.20-pre3/arch/i386/mm/Makefile
--- linux-2.4.20-pre2/arch/i386/mm/Makefile	Fri Dec 29 14:07:20 2000
+++ linux-2.4.20-pre3/arch/i386/mm/Makefile	Sat Aug 17 14:18:41 2002
@@ -9,6 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y	 := init.o fault.o ioremap.o extable.o
+obj-y	 := init.o fault.o ioremap.o extable.o pageattr.o
+export-objs := pageattr.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre2/arch/i386/mm/fault.c linux-2.4.20-pre3/arch/i386/mm/fault.c
--- linux-2.4.20-pre2/arch/i386/mm/fault.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/i386/mm/fault.c	Sat Aug 17 14:18:41 2002
@@ -86,8 +86,7 @@
 
 out_of_memory:
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		goto survive;
 	}
 	goto bad_area;
@@ -336,8 +335,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/i386/mm/pageattr.c linux-2.4.20-pre3/arch/i386/mm/pageattr.c
--- linux-2.4.20-pre2/arch/i386/mm/pageattr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/arch/i386/mm/pageattr.c	Sat Aug 17 14:18:41 2002
@@ -0,0 +1,172 @@
+/* 
+ * Copyright 2002 Andi Kleen, SuSE Labs. 
+ * Thanks to Ben LaHaise for precious feedback.
+ */ 
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+/* Should move most of this stuff into the appropiate includes */
+#define PAGE_LARGE (_PAGE_PSE|_PAGE_PRESENT) 
+#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+
+static inline pte_t *lookup_address(unsigned long address) 
+{ 
+	pmd_t *pmd;	
+	pgd_t *pgd = pgd_offset(&init_mm, address); 
+
+	if ((pgd_val(*pgd) & PAGE_LARGE) == PAGE_LARGE)
+		return (pte_t *)pgd; 
+	pmd = pmd_offset(pgd, address); 	       
+	if ((pmd_val(*pmd) & PAGE_LARGE) == PAGE_LARGE)
+		return (pte_t *)pmd; 
+
+        return pte_offset(pmd, address);
+} 
+
+static struct page *split_large_page(unsigned long address, pgprot_t prot)
+{ 
+	int i; 
+	unsigned long addr;
+	struct page *base = alloc_pages(GFP_KERNEL, 0);
+	pte_t *pbase;
+	if (!base) 
+		return NULL;
+	address = __pa(address);
+	addr = address & LARGE_PAGE_MASK; 
+	pbase = (pte_t *)page_address(base);
+	for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
+		pbase[i] = mk_pte_phys(addr, 
+				      addr == address ? prot : PAGE_KERNEL);
+	}
+	return base;
+} 
+
+static void flush_kernel_map(void * address) 
+{ 
+	if (!test_bit(X86_FEATURE_SELFSNOOP, &boot_cpu_data.x86_capability)) {
+		/* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */
+		if (boot_cpu_data.x86_model >= 4) 
+			asm volatile("wbinvd":::"memory"); 	
+	} 
+
+	/* Do global flush here to work around large page flushing errata 
+	   in some early Athlons */
+	__flush_tlb_all(); 	
+}
+
+static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) 
+{ 
+	set_pte_atomic(kpte, pte); 	/* change init_mm */
+#ifndef CONFIG_X86_PAE
+	{
+		struct list_head *l;
+		spin_lock(&mmlist_lock);
+		list_for_each(l, &init_mm.mmlist) { 
+			struct mm_struct *mm = list_entry(l, struct mm_struct, mmlist);
+			pmd_t *pmd = pmd_offset(pgd_offset(mm, address), address);
+			set_pte_atomic((pte_t *)pmd, pte);
+		} 
+		spin_unlock(&mmlist_lock);
+	}
+#endif
+}
+
+/* no more special protections in this 2/4MB area - revert to a
+   large page again. */
+static inline void revert_page(struct page *kpte_page, unsigned long address)
+{
+	pte_t *linear = (pte_t *) 
+		pmd_offset(pgd_offset(&init_mm, address), address);
+	set_pmd_pte(linear,  address,
+		mk_pte_phys(__pa(address & LARGE_PAGE_MASK),
+			    MAKE_GLOBAL(_KERNPG_TABLE|_PAGE_PSE)));
+}	
+ 
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * This should be used when a page is mapped with a different caching policy
+ * than write-back somewhere - some CPUs do not like it when mappings with
+ * different caching policies exist. This changes the page attributes of the
+ * in kernel linear mapping too.
+ * 
+ * The caller needs to ensure that there are no conflicting mappings elsewhere.
+ * This function only deals with the kernel linear map.
+ * When page is in highmem it must never be kmap'ed.
+ */
+static int 
+__change_page_attr(struct page *page, pgprot_t prot, struct page **oldpage) 
+{ 
+	pte_t *kpte; 
+	unsigned long address;
+	struct page *kpte_page;
+
+#ifdef CONFIG_HIGHMEM
+	if (page >= highmem_start_page) 
+		BUG(); 
+#endif
+	address = (unsigned long)page_address(page);
+
+	kpte = lookup_address(address);
+	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
+		if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+			pte_t old = *kpte;
+			pte_t standard = mk_pte(page, PAGE_KERNEL); 
+
+			set_pte_atomic(kpte, mk_pte(page, prot)); 
+			if (pte_same(old,standard))
+				atomic_inc(&kpte_page->count);
+		} else {
+			struct page *split = split_large_page(address, prot); 
+			if (!split)
+				return -ENOMEM;
+			set_pmd_pte(kpte,address,mk_pte(split, PAGE_KERNEL));
+		}	
+	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+		set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
+		atomic_dec(&kpte_page->count); 
+	}
+
+	if (test_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability) && 
+	    (atomic_read(&kpte_page->count) == 1)) { 
+		*oldpage = kpte_page;
+		revert_page(kpte_page, address);
+	} 
+	return 0;
+} 
+
+int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+	int err = 0; 
+	struct page *fpage; 
+	int i; 
+
+	down_write(&init_mm.mmap_sem);
+	for (i = 0; i < numpages; i++, page++) { 
+		fpage = NULL;
+		err = __change_page_attr(page, prot, &fpage); 
+		if (err) 
+			break; 
+		if (fpage || i == numpages-1) { 
+			void *address = page_address(page);
+#ifdef CONFIG_SMP 
+			smp_call_function(flush_kernel_map, address, 1, 1);
+#endif	
+			flush_kernel_map(address);
+			if (fpage)
+				__free_page(fpage);
+		} 
+	} 	
+	up_write(&init_mm.mmap_sem); 
+	return err;
+}
+
+EXPORT_SYMBOL(change_page_attr);
diff -urN linux-2.4.20-pre2/arch/ia64/mm/fault.c linux-2.4.20-pre3/arch/ia64/mm/fault.c
--- linux-2.4.20-pre2/arch/ia64/mm/fault.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre3/arch/ia64/mm/fault.c	Sat Aug 17 14:18:41 2002
@@ -196,8 +196,7 @@
   out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/m68k/mm/fault.c linux-2.4.20-pre3/arch/m68k/mm/fault.c
--- linux-2.4.20-pre2/arch/m68k/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/m68k/mm/fault.c	Sat Aug 17 14:18:41 2002
@@ -181,8 +181,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/mips/mm/fault.c linux-2.4.20-pre3/arch/mips/mm/fault.c
--- linux-2.4.20-pre2/arch/mips/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/mips/mm/fault.c	Sat Aug 17 14:18:41 2002
@@ -213,8 +213,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/mips64/mm/fault.c linux-2.4.20-pre3/arch/mips64/mm/fault.c
--- linux-2.4.20-pre2/arch/mips64/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/mips64/mm/fault.c	Sat Aug 17 14:18:41 2002
@@ -238,8 +238,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/ppc/kernel/pci.c linux-2.4.20-pre3/arch/ppc/kernel/pci.c
--- linux-2.4.20-pre2/arch/ppc/kernel/pci.c	Sat Aug 17 14:18:12 2002
+++ linux-2.4.20-pre3/arch/ppc/kernel/pci.c	Sat Aug 17 14:18:44 2002
@@ -925,7 +925,7 @@
 	/* XXX FIXME - update OF device tree node interrupt property */
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -938,6 +938,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		if(!(mask & (1<<idx)))
+			continue;
+			
 		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);
diff -urN linux-2.4.20-pre2/arch/ppc/mm/fault.c linux-2.4.20-pre3/arch/ppc/mm/fault.c
--- linux-2.4.20-pre2/arch/ppc/mm/fault.c	Tue Oct  2 09:12:44 2001
+++ linux-2.4.20-pre3/arch/ppc/mm/fault.c	Sat Aug 17 14:18:44 2002
@@ -197,8 +197,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/ppc64/kernel/pci.c linux-2.4.20-pre3/arch/ppc64/kernel/pci.c
--- linux-2.4.20-pre2/arch/ppc64/kernel/pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/ppc64/kernel/pci.c	Sat Aug 17 14:18:45 2002
@@ -364,7 +364,7 @@
 
 
 int
-pcibios_enable_resources(struct pci_dev *dev)
+pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -587,6 +587,8 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		if(!(mask & (1<<idx)))
+			continue;
 		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);
diff -urN linux-2.4.20-pre2/arch/s390/mm/fault.c linux-2.4.20-pre3/arch/s390/mm/fault.c
--- linux-2.4.20-pre2/arch/s390/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/s390/mm/fault.c	Sat Aug 17 14:18:45 2002
@@ -293,8 +293,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/s390x/mm/fault.c linux-2.4.20-pre3/arch/s390x/mm/fault.c
--- linux-2.4.20-pre2/arch/s390x/mm/fault.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/arch/s390x/mm/fault.c	Sat Aug 17 14:18:45 2002
@@ -293,8 +293,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/sh/mm/fault.c linux-2.4.20-pre3/arch/sh/mm/fault.c
--- linux-2.4.20-pre2/arch/sh/mm/fault.c	Mon Oct 15 13:36:48 2001
+++ linux-2.4.20-pre3/arch/sh/mm/fault.c	Sat Aug 17 14:18:45 2002
@@ -207,8 +207,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff -urN linux-2.4.20-pre2/arch/x86_64/mm/fault.c linux-2.4.20-pre3/arch/x86_64/mm/fault.c
--- linux-2.4.20-pre2/arch/x86_64/mm/fault.c	Sat Aug 17 14:18:15 2002
+++ linux-2.4.20-pre3/arch/x86_64/mm/fault.c	Sat Aug 17 14:18:46 2002
@@ -270,8 +270,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (current->pid == 1) { 
-		tsk->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		goto again;
 	}
 	printk("VM: killing process %s\n", tsk->comm);
diff -urN linux-2.4.20-pre2/drivers/acpi/ospm/system/sm_osl.c linux-2.4.20-pre3/drivers/acpi/ospm/system/sm_osl.c
--- linux-2.4.20-pre2/drivers/acpi/ospm/system/sm_osl.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.20-pre3/drivers/acpi/ospm/system/sm_osl.c	Sat Aug 17 14:18:46 2002
@@ -685,6 +685,9 @@
 	 */
 	if (state == ACPI_S2 || state == ACPI_S3) {
 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
+		/* That && trick is *not going to work*. Read gcc
+		   specs. That explicitely says: jumping from other
+		   function is *not allowed*. */ 
 		wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done);
 
 		if (!wakeup_address) goto acpi_sleep_done;
diff -urN linux-2.4.20-pre2/drivers/atm/firestream.c linux-2.4.20-pre3/drivers/atm/firestream.c
--- linux-2.4.20-pre2/drivers/atm/firestream.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.20-pre3/drivers/atm/firestream.c	Sat Aug 17 14:18:46 2002
@@ -330,8 +330,8 @@
 #define FS_DEBUG_QSIZE   0x00001000
 
 
-#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter " __FUNCTION__ "\n")
-#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  " __FUNCTION__ "\n")
+#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter %s\n", __FUNCTION__)
+#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  %s\n", __FUNCTION__)
 
 
 struct fs_dev *fs_boards = NULL;
@@ -760,6 +760,7 @@
 		default:
 			/* Here we get the tx purge inhibit command ... */
 			/* Action, I believe, is "don't do anything". -- REW */
+			break;
 		}
     
 		write_fs (dev, Q_RP(q->offset), Q_INCWRAP);
diff -urN linux-2.4.20-pre2/drivers/block/DAC960.c linux-2.4.20-pre3/drivers/block/DAC960.c
--- linux-2.4.20-pre2/drivers/block/DAC960.c	Sat Aug 17 14:18:16 2002
+++ linux-2.4.20-pre3/drivers/block/DAC960.c	Sat Aug 17 14:18:46 2002
@@ -5544,7 +5544,7 @@
 static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File,
 			    unsigned int Request, unsigned long Argument)
 {
-  int ErrorCode;
+  int ErrorCode = 0 ;
   if (!capable(CAP_SYS_ADMIN)) return -EACCES;
   switch (Request)
     {
@@ -5595,9 +5595,11 @@
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_V1_UserCommand_T));
-	if (ErrorCode != 0) goto Failure1;
+	if (copy_from_user(&UserCommand, UserSpaceUserCommand,
+				   sizeof(DAC960_V1_UserCommand_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	}
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5610,9 +5612,11 @@
 	if (CommandOpcode & 0x80) return -EINVAL;
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
-	    ErrorCode =
-	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T));
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_from_user(&DCDB, UserCommand.DCDB,
+			       sizeof(DAC960_V1_DCDB_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	    if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
 	    if (!((DataTransferLength == 0 &&
 		   DCDB.Direction
@@ -5638,10 +5642,12 @@
 	  {
 	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
 	    if (DataTransferBuffer == NULL) return -ENOMEM;
-	    ErrorCode = copy_from_user(DataTransferBuffer,
-				       UserCommand.DataTransferBuffer,
-				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_from_user(DataTransferBuffer,
+			       UserCommand.DataTransferBuffer,
+			       -DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
@@ -5689,17 +5695,20 @@
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	if (DataTransferLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
-				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_to_user(UserCommand.DataTransferBuffer,
+			     DataTransferBuffer, DataTransferLength))
+		ErrorCode = -EFAULT;
+		goto Failure1;
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = false;
-	    ErrorCode =
-	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_V1_DCDB_T));
-	    if (ErrorCode != 0) goto Failure1;
+	    if (copy_to_user(UserCommand.DCDB, &DCDB,
+			     sizeof(DAC960_V1_DCDB_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure1;
+	    }
 	  }
 	ErrorCode = CommandStatus;
       Failure1:
@@ -5722,9 +5731,11 @@
 	unsigned char *DataTransferBuffer = NULL;
 	unsigned char *RequestSenseBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_V2_UserCommand_T));
-	if (ErrorCode != 0) goto Failure2;
+	if (copy_from_user(&UserCommand, UserSpaceUserCommand,
+			   sizeof(DAC960_V2_UserCommand_T))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5743,10 +5754,12 @@
 	  {
 	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
 	    if (DataTransferBuffer == NULL) return -ENOMEM;
-	    ErrorCode = copy_from_user(DataTransferBuffer,
-				       UserCommand.DataTransferBuffer,
-				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_from_user(DataTransferBuffer,
+			       UserCommand.DataTransferBuffer,
+			       -DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	RequestSenseLength = UserCommand.RequestSenseLength;
 	if (RequestSenseLength > 0)
@@ -5816,25 +5829,32 @@
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	if (RequestSenseLength > UserCommand.RequestSenseLength)
 	  RequestSenseLength = UserCommand.RequestSenseLength;
-	ErrorCode = copy_to_user(&UserSpaceUserCommand->DataTransferLength,
+	if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
 				 &DataTransferResidue,
-				 sizeof(DataTransferResidue));
-	if (ErrorCode != 0) goto Failure2;
-	ErrorCode = copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
-				 &RequestSenseLength,
-				 sizeof(RequestSenseLength));
-	if (ErrorCode != 0) goto Failure2;
+				 sizeof(DataTransferResidue))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
+	if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
+			 &RequestSenseLength, sizeof(RequestSenseLength))) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	}
 	if (DataTransferLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
-				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_to_user(UserCommand.DataTransferBuffer,
+			     DataTransferBuffer, DataTransferLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	if (RequestSenseLength > 0)
 	  {
-	    ErrorCode = copy_to_user(UserCommand.RequestSenseBuffer,
-				     RequestSenseBuffer, RequestSenseLength);
-	    if (ErrorCode != 0) goto Failure2;
+	    if (copy_to_user(UserCommand.RequestSenseBuffer,
+			     RequestSenseBuffer, RequestSenseLength)) {
+		ErrorCode = -EFAULT;
+		goto Failure2;
+	    }
 	  }
 	ErrorCode = CommandStatus;
       Failure2:
@@ -5853,9 +5873,9 @@
 	DAC960_Controller_T *Controller;
 	int ControllerNumber;
 	if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
-	ErrorCode = copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
-				   sizeof(DAC960_V2_GetHealthStatus_T));
-	if (ErrorCode != 0) return ErrorCode;
+	if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
+			   sizeof(DAC960_V2_GetHealthStatus_T)))
+		return -EFAULT;
 	ControllerNumber = GetHealthStatus.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
@@ -5863,10 +5883,10 @@
 	Controller = DAC960_Controllers[ControllerNumber];
 	if (Controller == NULL) return -ENXIO;
 	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
-	ErrorCode = copy_from_user(&HealthStatusBuffer,
-				   GetHealthStatus.HealthStatusBuffer,
-				   sizeof(DAC960_V2_HealthStatusBuffer_T));
-	if (ErrorCode != 0) return ErrorCode;
+	if (copy_from_user(&HealthStatusBuffer,
+			   GetHealthStatus.HealthStatusBuffer,
+			   sizeof(DAC960_V2_HealthStatusBuffer_T)))
+		return -EFAULT;
 	while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
 	       == HealthStatusBuffer.StatusChangeCounter &&
 	       Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
@@ -5876,10 +5896,11 @@
 					   DAC960_MonitoringTimerInterval);
 	    if (signal_pending(current)) return -EINTR;
 	  }
-	ErrorCode = copy_to_user(GetHealthStatus.HealthStatusBuffer,
-				 Controller->V2.HealthStatusBuffer,
-				 sizeof(DAC960_V2_HealthStatusBuffer_T));
-	return ErrorCode;
+	if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
+			 Controller->V2.HealthStatusBuffer,
+			 sizeof(DAC960_V2_HealthStatusBuffer_T)))
+		return -EFAULT;
+	return 0;
       }
     }
   return -EINVAL;
diff -urN linux-2.4.20-pre2/drivers/block/cpqarray.c linux-2.4.20-pre3/drivers/block/cpqarray.c
--- linux-2.4.20-pre2/drivers/block/cpqarray.c	Sat Aug 17 14:18:16 2002
+++ linux-2.4.20-pre3/drivers/block/cpqarray.c	Sat Aug 17 14:18:46 2002
@@ -1141,8 +1141,12 @@
         }
 
 	complete_buffers(cmd->rq->bh, ok);
+
 	DBGPX(printk("Done with %p\n", cmd->rq););
+	req_finished_io(cmd->rq);
 	end_that_request_last(cmd->rq);
+
+
 }
 
 /*
diff -urN linux-2.4.20-pre2/drivers/block/elevator.c linux-2.4.20-pre3/drivers/block/elevator.c
--- linux-2.4.20-pre2/drivers/block/elevator.c	Thu Jul 19 20:59:41 2001
+++ linux-2.4.20-pre3/drivers/block/elevator.c	Sat Aug 17 14:18:46 2002
@@ -82,54 +82,55 @@
 {
 	struct list_head *entry = &q->queue_head;
 	unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
+	struct request *__rq;
+	int merge_only = 0;
 
 	while ((entry = entry->prev) != head) {
-		struct request *__rq = blkdev_entry_to_request(entry);
+		__rq = blkdev_entry_to_request(entry);
 
 		/*
-		 * simply "aging" of requests in queue
+		 * we can't insert beyond a zero sequence point
 		 */
-		if (__rq->elevator_sequence-- <= 0)
-			break;
+		if (__rq->elevator_sequence <= 0)
+			merge_only = 1;
 
 		if (__rq->waiting)
 			continue;
 		if (__rq->rq_dev != bh->b_rdev)
 			continue;
-		if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head))
+		if (!*req && !merge_only && bh_rq_in_between(bh, __rq, &q->queue_head))
 			*req = __rq;
 		if (__rq->cmd != rw)
 			continue;
 		if (__rq->nr_sectors + count > max_sectors)
 			continue;
-		if (__rq->elevator_sequence < count)
-			break;
 		if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
 			ret = ELEVATOR_BACK_MERGE;
 			*req = __rq;
 			break;
 		} else if (__rq->sector - count == bh->b_rsector) {
 			ret = ELEVATOR_FRONT_MERGE;
-			__rq->elevator_sequence -= count;
+			__rq->elevator_sequence--;
 			*req = __rq;
 			break;
 		}
 	}
 
-	return ret;
-}
-
-void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int count)
-{
-	struct list_head *entry = &req->queue, *head = &q->queue_head;
-
 	/*
-	 * second pass scan of requests that got passed over, if any
+	 * account merge (ret != 0, cost is 1) or seeky insert (*req is set,
+	 * cost is ELV_LINUS_SEEK_COST
 	 */
-	while ((entry = entry->next) != head) {
-		struct request *tmp = blkdev_entry_to_request(entry);
-		tmp->elevator_sequence -= count;
+	if (*req) {
+		int scan_cost = ret ? 1 : ELV_LINUS_SEEK_COST;
+		struct list_head *entry = &(*req)->queue;
+
+		while ((entry = entry->next) != &q->queue_head) {
+			__rq = blkdev_entry_to_request(entry);
+			__rq->elevator_sequence -= scan_cost;
+		}
 	}
+
+	return ret;
 }
 
 void elevator_linus_merge_req(struct request *req, struct request *next)
@@ -177,8 +178,6 @@
 	return ELEVATOR_NO_MERGE;
 }
 
-void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {}
-
 void elevator_noop_merge_req(struct request *req, struct request *next) {}
 
 int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
diff -urN linux-2.4.20-pre2/drivers/block/ll_rw_blk.c linux-2.4.20-pre3/drivers/block/ll_rw_blk.c
--- linux-2.4.20-pre2/drivers/block/ll_rw_blk.c	Sat Aug 17 14:18:16 2002
+++ linux-2.4.20-pre3/drivers/block/ll_rw_blk.c	Sat Aug 17 14:18:46 2002
@@ -972,7 +972,6 @@
 				insert_here = &req->queue;
 				break;
 			}
-			elevator->elevator_merge_cleanup_fn(q, req, count);
 			req->bhtail->b_reqnext = bh;
 			req->bhtail = bh;
 			req->nr_sectors = req->hard_nr_sectors += count;
@@ -987,7 +986,6 @@
 				insert_here = req->queue.prev;
 				break;
 			}
-			elevator->elevator_merge_cleanup_fn(q, req, count);
 			bh->b_reqnext = req->bh;
 			req->bh = bh;
 			/*
diff -urN linux-2.4.20-pre2/drivers/block/ps2esdi.c linux-2.4.20-pre3/drivers/block/ps2esdi.c
--- linux-2.4.20-pre2/drivers/block/ps2esdi.c	Fri Nov  9 14:01:21 2001
+++ linux-2.4.20-pre3/drivers/block/ps2esdi.c	Sat Aug 17 14:18:46 2002
@@ -466,7 +466,6 @@
 	u_int block, count;
 	/* since, this routine is called with interrupts cleared - they 
 	   must be before it finishes  */
-	sti();
 
 #if 0
 	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
@@ -563,6 +562,7 @@
 
 	u_short track, head, cylinder, sector;
 	u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
+	int err;
 
 	/* do some relevant arithmatic */
 	track = block / ps2esdi_info[drive].sect;
@@ -580,9 +580,13 @@
 	     cylinder, head, sector,
 	     CURRENT->current_nr_sectors, drive);
 
+	spin_unlock_irq(&io_request_irq);
 	/* send the command block to the controller */
-	if (ps2esdi_out_cmd_blk(cmd_blk)) {
-		printk("%s: Controller failed\n", DEVICE_NAME);
+	err = ps2esdi_out_cmd_blk(cmd_blk);
+	spin_lock_irq(&io_request_irq);
+	
+	if (err) {
+		printk(KERN_ERR "%s: Controller failed\n", DEVICE_NAME);
 		if ((++CURRENT->errors) >= MAX_RETRIES)
 			end_request(FAIL);
 	}
@@ -1135,9 +1139,7 @@
 	int start = target << ps2esdi_gendisk.minor_shift;
 	int partition;
 
-	cli();
 	ps2esdi_valid[target] = (access_count[target] != 1);
-	sti();
 	if (ps2esdi_valid[target])
 		return (-EBUSY);
 
diff -urN linux-2.4.20-pre2/drivers/block/xd.c linux-2.4.20-pre3/drivers/block/xd.c
--- linux-2.4.20-pre2/drivers/block/xd.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/drivers/block/xd.c	Sat Aug 17 14:18:46 2002
@@ -144,32 +144,40 @@
 	release:	xd_release,
 	ioctl:		xd_ioctl,
 };
+
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
-static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
-static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
-static u_char xd_override __initdata = 0, xd_type __initdata = 0;
-static u_short xd_iobase = 0x320;
+static u8 xd_valid[XD_MAXDRIVES] = { 0,0 };
+static u8 xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
+static u8 xd_override __initdata = 0, xd_type __initdata = 0;
+static u16 xd_iobase = 0x320;
 static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
 
 static volatile int xdc_busy;
-static DECLARE_WAIT_QUEUE_HEAD(xdc_wait);
 
-static struct timer_list xd_timer, xd_watchdog_int;
+static struct timer_list xd_watchdog_int;
 
-static volatile u_char xd_error;
+static volatile u8 xd_error;
 static int nodma = XD_DONT_USE_DMA;
 
 static devfs_handle_t devfs_handle = NULL;
 
 /* xd_init: register the block device number and set up pointer tables */
-int __init xd_init (void)
+int __init xd_init(void)
 {
-	init_timer (&xd_timer); xd_timer.function = xd_wakeup;
-	init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
+	init_timer (&xd_watchdog_int); 
+	xd_watchdog_int.function = xd_watchdog;
+
+	if (!xd_dma_buffer)
+		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+	if (!xd_dma_buffer)
+	{
+		printk(KERN_ERR "xd: Out of memory.\n");
+		return -ENOMEM;
+	}
 
 	if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
-		printk("xd: Unable to get major number %d\n",MAJOR_NR);
+		printk(KERN_ERR "xd: Unable to get major number %d\n",MAJOR_NR);
 		return -1;
 	}
 	devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL);
@@ -182,9 +190,10 @@
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char __init xd_detect (u_char *controller, unsigned int *address)
+
+static u8 __init xd_detect (u8 *controller, unsigned int *address)
 {
-	u_char i,j,found = 0;
+	u8 i,j,found = 0;
 
 	if (xd_override)
 	{
@@ -206,32 +215,32 @@
 
 /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 /* and set up the "raw" device entries in the table */
+
 static void __init xd_geninit (void)
 {
-	u_char i,controller;
+	u8 i,controller;
 	unsigned int address;
 
-	for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
+	for(i=0;i<(XD_MAXDRIVES << 6);i++)
+		xd_blocksizes[i] = 1024;
+		
 	blksize_size[MAJOR_NR] = xd_blocksizes;
 
 	if (xd_detect(&controller,&address)) {
-
-		printk("Detected a%s controller (type %d) at address %06x\n",
+		printk(KERN_INFO "Detected a%s controller (type %d) at address %06x\n",
 			xd_sigs[controller].name,controller,address);
-		if (check_region(xd_iobase,4)) {
-			printk("xd: Ports at 0x%x are not available\n",
-				xd_iobase);
+		if (!request_region(xd_iobase,4, "xd")) {
+			printk(KERN_ERR "xd: Ports at 0x%x are not available\n", xd_iobase);
 			return;
 		}
-		request_region(xd_iobase,4,"xd");
 		if (controller)
 			xd_sigs[controller].init_controller(address);
 		xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
 		
-		printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
+		printk(KERN_INFO "Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
 			xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
 		for (i = 0; i < xd_drives; i++)
-			printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,
+			printk(KERN_INFO " xd%c: CHS=%d/%d/%d\n",'a'+i,
 				xd_info[i].cylinders,xd_info[i].heads,
 				xd_info[i].sectors);
 
@@ -239,12 +248,12 @@
 	if (xd_drives) {
 		if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
 			if (request_dma(xd_dma,"xd")) {
-				printk("xd: unable to get DMA%d\n",xd_dma);
+				printk(KERN_ERR "xd: unable to get DMA%d\n",xd_dma);
 				free_irq(xd_irq, NULL);
 			}
 		}
 		else
-			printk("xd: unable to get IRQ%d\n",xd_irq);
+			printk(KERN_ERR "xd: unable to get IRQ%d\n",xd_irq);
 	}
 
 	/* xd_maxsectors depends on controller - so set after detection */
@@ -270,9 +279,7 @@
 	if (dev < xd_drives) {
 		while (!xd_valid[dev])
 			sleep_on(&xd_wait_open);
-
 		xd_access[dev]++;
-
 		return (0);
 	}
 
@@ -282,18 +289,16 @@
 /* do_xd_request: handle an incoming request */
 static void do_xd_request (request_queue_t * q)
 {
-	u_int block,count,retry;
+	unsigned int block,count,retry;
 	int code;
 
-	sti();
 	if (xdc_busy)
 		return;
+		
 	while (code = 0, !QUEUE_EMPTY) {
 		INIT_REQUEST;	/* do some checking on the request structure */
 
-		if (CURRENT_DEV < xd_drives
-		    && CURRENT->sector + CURRENT->nr_sectors
-		         <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
+		if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
 			block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect;
 			count = CURRENT->nr_sectors;
 
@@ -304,8 +309,7 @@
 						code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 					break;
 				default:
-					printk("do_xd_request: unknown request\n");
-					break;
+					BUG();
 			}
 		}
 		end_request(code);	/* wrap up, 0 = fail, 1 = success */
@@ -313,7 +317,8 @@
 }
 
 /* xd_ioctl: handle device ioctl's */
-static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
+
+static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
 {
 	int dev;
 
@@ -327,7 +332,6 @@
 		{
 			struct hd_geometry g;
 			struct hd_geometry *geometry = (struct hd_geometry *) arg;
-			if (!geometry) return -EINVAL;
 			g.heads = xd_info[dev].heads;
 			g.sectors = xd_info[dev].sectors;
 			g.cylinders = xd_info[dev].cylinders;
@@ -335,12 +339,23 @@
 			return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
 		}
 		case HDIO_SET_DMA:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (xdc_busy) return -EBUSY;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			if (xdc_busy)
+				return -EBUSY;
+				
 			nodma = !arg;
+			
 			if (nodma && xd_dma_buffer) {
 				xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
 				xd_dma_buffer = 0;
+			} else if (!nodma && !xd_dma_buffer) {
+				xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
+				if (!xd_dma_buffer)
+				{
+					nodma = XD_DONT_USE_DMA;
+					return -ENOMEM;
+				}
 			}
 			return 0;
 		case HDIO_GET_DMA:
@@ -351,7 +366,6 @@
 			if (!capable(CAP_SYS_ADMIN)) 
 				return -EACCES;
 			return xd_reread_partitions(inode->i_rdev);
-
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
 		case BLKFLSBUF:
@@ -361,7 +375,6 @@
 		case BLKRAGET:
 		case BLKPG:
 			return blk_ioctl(inode->i_rdev, cmd, arg);
-
 		default:
 			return -EINVAL;
 	}
@@ -409,21 +422,20 @@
 }
 
 /* xd_readwrite: handle a read/write request */
-static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
+static int xd_readwrite (u8 operation,u8 drive,char *buffer,unsigned int block,unsigned int count)
 {
-	u_char cmdblk[6],sense[4];
-	u_short track,cylinder;
-	u_char head,sector,control,mode = PIO_MODE,temp;
+	u8 cmdblk[6],sense[4];
+	u16 track,cylinder;
+	u8 head,sector,control,mode = PIO_MODE,temp;
 	char **real_buffer;
-	register int i;
 	
 #ifdef DEBUG_READWRITE
-	printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
+	printk(KERN_DEBUG "xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 #endif /* DEBUG_READWRITE */
 
+	spin_unlock_irq(&io_request_lock);
+
 	control = xd_info[drive].control;
-	if (!xd_dma_buffer)
-		xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
 	while (count) {
 		temp = count < xd_maxsectors ? count : xd_maxsectors;
 
@@ -433,28 +445,28 @@
 		sector = block % xd_info[drive].sectors;
 
 #ifdef DEBUG_READWRITE
-		printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
+		printk(KERN_DEBUG "xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 #endif /* DEBUG_READWRITE */
 
 		if (xd_dma_buffer) {
-			mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
+			mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u8 *)(xd_dma_buffer),temp * 0x200);
 			real_buffer = &xd_dma_buffer;
-			for (i=0; i < (temp * 0x200); i++)
-				xd_dma_buffer[i] = buffer[i];
+			memcpy(xd_dma_buffer, buffer, temp * 0x200);
 		}
 		else
 			real_buffer = &buffer;
 
 		xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 
-		switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
+		switch (xd_command(cmdblk,mode,(u8 *)(*real_buffer),(u8 *)(*real_buffer),sense,XD_TIMEOUT)) 
+		{
 			case 1:
-				printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
+				printk(KERN_WARNING "xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
 				xd_recalibrate(drive);
-				return (0);
+				goto fail;
 			case 2:
 				if (sense[0] & 0x30) {
-					printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
+					printk(KERN_ERR "xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
 					switch ((sense[0] & 0x30) >> 4) {
 					case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
 						break;
@@ -471,25 +483,30 @@
 				/*	reported drive number = (sense[1] & 0xE0) >> 5 */
 				else
 					printk(" - no valid disk address\n");
-				return (0);
+				goto fail;
 		}
 		if (xd_dma_buffer)
-			for (i=0; i < (temp * 0x200); i++)
-				buffer[i] = xd_dma_buffer[i];
+			memcpy(buffer, xd_dma_buffer, (temp * 0x200));
 
 		count -= temp, buffer += temp * 0x200, block += temp;
 	}
-	return (1);
+	spin_lock_irq(&io_request_lock);
+	return 1;
+
+fail:
+	spin_lock_irq(&io_request_lock);
+	return 0;
+
 }
 
 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
-static void xd_recalibrate (u_char drive)
+static void xd_recalibrate (u8 drive)
 {
-	u_char cmdblk[6];
+	u8 cmdblk[6];
 	
 	xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 	if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
-		printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
+		printk(KERN_WARNING "xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
 }
 
 /* xd_interrupt_handler: interrupt service routine */
@@ -497,17 +514,17 @@
 {
 	if (inb(XD_STATUS) & STAT_INTERRUPT) {							/* check if it was our device */
 #ifdef DEBUG_OTHER
-		printk("xd_interrupt_handler: interrupt detected\n");
+		printk(KERN_DEBUG "xd_interrupt_handler: interrupt detected\n");
 #endif /* DEBUG_OTHER */
 		outb(0,XD_CONTROL);								/* acknowledge interrupt */
 		wake_up(&xd_wait_int);								/* and wake up sleeping processes */
 	}
 	else
-		printk("xd: unexpected interrupt\n");
+		printk(KERN_DEBUG "xd: unexpected interrupt\n");
 }
 
 /* xd_setup_dma: set up the DMA controller for a data transfer */
-static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
+static u8 xd_setup_dma (u8 mode,u8 *buffer,unsigned int count)
 {
 	unsigned long f;
 	
@@ -515,9 +532,9 @@
 		return (PIO_MODE);
 	if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
 #ifdef DEBUG_OTHER
-		printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
+		printk(KERN_DEBUG "xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 #endif /* DEBUG_OTHER */
-		return (PIO_MODE);
+		return PIO_MODE;
 	}
 	
 	f=claim_dma_lock();
@@ -529,11 +546,11 @@
 	
 	release_dma_lock(f);
 
-	return (DMA_MODE);			/* use DMA and INT */
+	return DMA_MODE;			/* use DMA and INT */
 }
 
 /* xd_build: put stuff into an array in a format suitable for the controller */
-static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
+static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control)
 {
 	cmdblk[0] = command;
 	cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
@@ -542,13 +559,7 @@
 	cmdblk[4] = count;
 	cmdblk[5] = control;
 	
-	return (cmdblk);
-}
-
-/* xd_wakeup is called from timer interrupt */
-static void xd_wakeup (unsigned long unused)
-{
-	wake_up(&xdc_wait);
+	return cmdblk;
 }
 
 /* xd_wakeup is called from timer interrupt */
@@ -559,25 +570,21 @@
 }
 
 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
+static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout)
 {
-	u_long expiry = jiffies + timeout;
+	unsigned long expiry = jiffies + timeout;
 	int success;
 
 	xdc_busy = 1;
 	while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) {
-		xd_timer.expires = jiffies;
-		cli();
-		add_timer(&xd_timer);
-		sleep_on(&xdc_wait);
-		del_timer(&xd_timer);
-		sti();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 	xdc_busy = 0;
 	return (success);
 }
 
-static inline u_int xd_wait_for_IRQ (void)
+static inline unsigned int xd_wait_for_IRQ (void)
 {
 	unsigned long flags;
 	xd_watchdog_int.expires = jiffies + 8 * HZ;
@@ -588,7 +595,7 @@
 	release_dma_lock(flags);
 	
 	sleep_on(&xd_wait_int);
-	del_timer(&xd_watchdog_int);
+	del_timer_sync(&xd_watchdog_int);
 	xdc_busy = 0;
 	
 	flags=claim_dma_lock();
@@ -596,7 +603,7 @@
 	release_dma_lock(flags);
 	
 	if (xd_error) {
-		printk("xd: missed IRQ - command aborted\n");
+		printk(KERN_DEBUG "xd: missed IRQ - command aborted\n");
 		xd_error = 0;
 		return (1);
 	}
@@ -604,12 +611,13 @@
 }
 
 /* xd_command: handle all data transfers necessary for a single command */
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
+static unsigned int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout)
 {
-	u_char cmdblk[6],csb,complete = 0;
+	u8 cmdblk[6];
+	u8 csb,complete = 0;
 
 #ifdef DEBUG_COMMAND
-	printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
+	printk(KERN_DEBUG "xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 #endif /* DEBUG_COMMAND */
 
 	outb(0,XD_SELECT);
@@ -656,55 +664,57 @@
 	if (csb & CSB_ERROR) {									/* read sense data if error */
 		xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 		if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
-			printk("xd: warning! sense command failed!\n");
+			printk(KERN_DEBUG "xd: warning! sense command failed!\n");
 	}
 
 #ifdef DEBUG_COMMAND
-	printk("xd_command: completed with csb = 0x%X\n",csb);
+	printk(KERN_DEBUG "xd_command: completed with csb = 0x%X\n",csb);
 #endif /* DEBUG_COMMAND */
 
 	return (csb & CSB_ERROR);
 }
 
-static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
+static u8 __init xd_initdrives (void (*init_drive)(u8 drive))
 {
-	u_char cmdblk[6],i,count = 0;
+	u8 cmdblk[6],i,count = 0;
 
 	for (i = 0; i < XD_MAXDRIVES; i++) {
 		xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 		if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 
 			init_drive(count);
 			count++;
 
-	 		xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-			add_timer(&xd_timer);
-			sleep_on(&xdc_wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(XD_INIT_DISK_DELAY);
 		}
 	}
 	return (count);
 }
 
-static void __init xd_manual_geo_set (u_char drive)
+static void __init xd_manual_geo_set (u8 drive)
 {
-	xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
-	xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
-	xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
+	xd_info[drive].heads 	= xd_geo[3 * drive + 1];
+	xd_info[drive].cylinders= xd_geo[3 * drive];
+	xd_info[drive].sectors =  xd_geo[3 * drive + 2];
 }
 
 static void __init xd_dtc_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
-		case 0xC8000:	break;			/*initial: 0x320 */
-		case 0xCA000:	xd_iobase = 0x324; 
-		case 0xD0000:				/*5150CX*/
-		case 0xD8000:	break;			/*5150CX & 5150XL*/
-		default:        printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
-				break;
+		case 0xC8000:
+			break;			/*initial: 0x320 */
+		case 0xCA000:
+			xd_iobase = 0x324; 
+		case 0xD0000:			/*5150CX*/
+		case 0xD8000:
+			break;			/*5150CX & 5150XL*/
+		default:        
+			printk(KERN_ERR "xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
+			break;
 	}
 	xd_maxsectors = 0x01;		/* my card seems to have trouble doing multi-block transfers? */
 
@@ -712,10 +722,10 @@
 }
 
 
-static void __init xd_dtc5150cx_init_drive (u_char drive)
+static void __init xd_dtc5150cx_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
-	static u_short geometry_table[][4] = {
+	static u16 geometry_table[][4] = {
 		{0x200,8,0x200,0x100},
 		{0x267,2,0x267,0x267},
 		{0x264,4,0x264,0x80},
@@ -732,7 +742,7 @@
 		{0x2B9,5,0x2B9,0x2B9},
 		{0x280,6,0x280,0x100},
 		{0x132,4,0x132,0x0}};
-	u_char n;
+	u8 n;
 
 	n = inb(XD_JUMPER);
 	n = (drive ? n : (n >> 2)) & 0x33;
@@ -741,7 +751,7 @@
 		xd_manual_geo_set(drive);
 	else
 		if (n != 7) {	
-			xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+			xd_info[drive].heads = (u8)(geometry_table[n][1]);			/* heads */
 			xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
 			xd_info[drive].sectors = 17;				/* sectors */
 #if 0
@@ -751,7 +761,7 @@
 #endif /* 0 */
 		}
 		else {
-			printk("xd%c: undetermined drive geometry\n",'a'+drive);
+			printk(KERN_WARNING "xd%c: undetermined drive geometry\n",'a'+drive);
 			return;
 		}
 	xd_info[drive].control = 5;				/* control byte */
@@ -759,31 +769,31 @@
 	xd_recalibrate(drive);
 }
 
-static void __init xd_dtc_init_drive (u_char drive)
+static void __init xd_dtc_init_drive (u8 drive)
 {
-	u_char cmdblk[6],buf[64];
+	u8 cmdblk[6],buf[64];
 
 	xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 		xd_info[drive].heads = buf[0x0A];			/* heads */
-		xd_info[drive].cylinders = ((u_short *) (buf))[0x04];	/* cylinders */
+		xd_info[drive].cylinders = ((u16 *) (buf))[0x04];	/* cylinders */
 		xd_info[drive].sectors = 17;				/* sectors */
 		if (xd_geo[3*drive])
 			xd_manual_geo_set(drive);
 #if 0
-		xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];	/* reduced write */
-		xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06];	/* write precomp */
+		xd_info[drive].rwrite = ((u16 *) (buf + 1))[0x05];	/* reduced write */
+		xd_info[drive].precomp = ((u16 *) (buf + 1))[0x06];	/* write precomp */
 		xd_info[drive].ecc = buf[0x0F];				/* ecc length */
 #endif /* 0 */
 		xd_info[drive].control = 0;				/* control byte */
 
-		xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
+		xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u16 *) (buf + 1))[0x05],((u16 *) (buf + 1))[0x06],buf[0x0F]);
 		xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 		if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
-			printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
+			printk(KERN_WARNING "xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
 	}
 	else
-		printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
 }
 
 static void __init xd_wd_init_controller (unsigned int address)
@@ -796,22 +806,21 @@
 		case 0xCE000:   xd_iobase = 0x32C; break;
 		case 0xD0000:	xd_iobase = 0x328; break; /* ? */
 		case 0xD8000:	xd_iobase = 0x32C; break; /* ? */
-		default:        printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
+		default:        printk(KERN_ERR "xd_wd_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	xd_maxsectors = 0x01;		/* this one doesn't wrap properly either... */
 
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
-static void __init xd_wd_init_drive (u_char drive)
+static void __init xd_wd_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS may be disabled */
-	static u_short geometry_table[][4] = {
+	static u16 geometry_table[][4] = {
 		{0x264,4,0x1C2,0x1C2},   /* common part */
 		{0x132,4,0x099,0x0},
 		{0x267,2,0x1C2,0x1C2},
@@ -827,9 +836,9 @@
 		{0x264,4,0x265,0x265},
 		{0x267,4,0x268,0x268}};
 
-	u_char cmdblk[6],buf[0x200];
-	u_char n = 0,rll,jumper_state,use_jumper_geo;
-	u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
+	u8 cmdblk[6],buf[0x200];
+	u8 n = 0,rll,jumper_state,use_jumper_geo;
+	u8 wd_1002 = (xd_sigs[xd_type].string[7] == '6');
 	
 	jumper_state = ~(inb(0x322));
 	if (jumper_state & 0x40)
@@ -838,13 +847,13 @@
 	xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 		xd_info[drive].heads = buf[0x1AF];				/* heads */
-		xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];	/* cylinders */
+		xd_info[drive].cylinders = ((u16 *) (buf + 1))[0xD6];	/* cylinders */
 		xd_info[drive].sectors = 17;					/* sectors */
 		if (xd_geo[3*drive])
 			xd_manual_geo_set(drive);
 #if 0
-		xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];		/* reduced write */
-		xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];		/* write precomp */
+		xd_info[drive].rwrite = ((u16 *) (buf))[0xD8];		/* reduced write */
+		xd_info[drive].wprecomp = ((u16 *) (buf))[0xDA];		/* write precomp */
 		xd_info[drive].ecc = buf[0x1B4];				/* ecc length */
 #endif /* 0 */
 		xd_info[drive].control = buf[0x1B5];				/* control byte */
@@ -856,7 +865,7 @@
 		else if (use_jumper_geo) {
 			n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
 			xd_info[drive].cylinders = geometry_table[n][0];
-			xd_info[drive].heads = (u_char)(geometry_table[n][1]);
+			xd_info[drive].heads = (u8)(geometry_table[n][1]);
 			xd_info[drive].control = rll ? 7 : 5;
 #if 0
 			xd_info[drive].rwrite = geometry_table[n][2];
@@ -870,7 +879,7 @@
 					geometry_table[n][2],geometry_table[n][3],0x0B);
 			else
 				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
-					((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+					((u16 *) (buf))[0xD8],((u16 *) (buf))[0xDA],buf[0x1B4]);
 		}
 	/* 1002 based RLL controller requests converted addressing, but reports physical 
 	   (physical 26 sec., logical 17 sec.) 
@@ -888,7 +897,7 @@
 		}
 	}
 	else
-		printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);	
+		printk(KERN_WARNING "xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);	
 
 }
 
@@ -900,7 +909,7 @@
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	xd_maxsectors = 0x40;
@@ -908,9 +917,9 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void __init xd_seagate_init_drive (u_char drive)
+static void __init xd_seagate_init_drive (u8 drive)
 {
-	u_char cmdblk[6],buf[0x200];
+	u8 cmdblk[6],buf[0x200];
 
 	xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 	if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
@@ -920,7 +929,7 @@
 		xd_info[drive].control = 0;					/* control byte */
 	}
 	else
-		printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
 }
 
 /* Omti support courtesy Dirk Melchers */
@@ -932,7 +941,7 @@
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_omti_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 	}
 	
@@ -941,7 +950,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void __init xd_omti_init_drive (u_char drive)
+static void __init xd_omti_init_drive (u8 drive)
 {
 	/* gets infos from drive */
 	xd_override_init_drive(drive);
@@ -972,22 +981,21 @@
 		case 0xDC000:
 		case 0xDE000:
 		case 0xE0000:	break;
-		default:	printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
+		default:	printk(KERN_ERR "xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
 				break;
 		}
 
 	xd_maxsectors = 0x01;
 	outb(0,XD_RESET);		/* reset the controller */
 
-	xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
-	add_timer(&xd_timer);
-	sleep_on(&xdc_wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(XD_INIT_DISK_DELAY);
 }
 
-static void __init xd_xebec_init_drive (u_char drive)
+static void __init xd_xebec_init_drive (u8 drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
-	static u_short geometry_table[][5] = {
+	static u16 geometry_table[][5] = {
 		{0x132,4,0x080,0x080,0x7},
 		{0x132,4,0x080,0x080,0x17},
 		{0x264,2,0x100,0x100,0x7},
@@ -1004,14 +1012,14 @@
 		{0x400,6,0x400,0x400,0x7},
 		{0x264,8,0x264,0x200,0x17},
 		{0x33E,7,0x33E,0x200,0x7}};
-	u_char n;
+	u8 n;
 
 	n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry 
 					is assumed for BOTH drives */
 	if (xd_geo[3*drive])
 		xd_manual_geo_set(drive);
 	else {
-		xd_info[drive].heads = (u_char)(geometry_table[n][1]);			/* heads */
+		xd_info[drive].heads = (u8)(geometry_table[n][1]);			/* heads */
 		xd_info[drive].cylinders = geometry_table[n][0];	/* cylinders */
 		xd_info[drive].sectors = 17;				/* sectors */
 #if 0
@@ -1027,10 +1035,10 @@
 
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-static void __init xd_override_init_drive (u_char drive)
+static void __init xd_override_init_drive (u8 drive)
 {
-	u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
-	u_char cmdblk[6],i;
+	u16 min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
+	u8 cmdblk[6],i;
 
 	if (xd_geo[3*drive])
 		xd_manual_geo_set(drive);
@@ -1038,7 +1046,7 @@
 		for (i = 0; i < 3; i++) {
 			while (min[i] != max[i] - 1) {
 				test[i] = (min[i] + max[i]) / 2;
-				xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
+				xd_build(cmdblk,CMD_SEEK,drive,(u8) test[0],(u16) test[1],(u8) test[2],0,0);
 				if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 					min[i] = test[i];
 				else
@@ -1046,9 +1054,9 @@
 			}
 			test[i] = min[i];
 		}
-		xd_info[drive].heads = (u_char) min[0] + 1;
-		xd_info[drive].cylinders = (u_short) min[1] + 1;
-		xd_info[drive].sectors = (u_char) min[2] + 1;
+		xd_info[drive].heads = (u8) min[0] + 1;
+		xd_info[drive].cylinders = (u16) min[1] + 1;
+		xd_info[drive].sectors = (u8) min[2] + 1;
 	}
 	xd_info[drive].control = 0;
 }
@@ -1069,30 +1077,30 @@
 			if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
 				xd_type = integers[1];
 		case 0: break;
-		default:printk("xd: too many parameters for xd\n");
+		default:printk(KERN_ERR "xd: too many parameters for xd\n");
 	}
 	xd_maxsectors = 0x01;
 }
 
 /* xd_setparam: set the drive characteristics */
-static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+static void __init xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc)
 {
-	u_char cmdblk[14];
+	u8 cmdblk[14];
 
 	xd_build(cmdblk,command,drive,0,0,0,0,0);
-	cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
-	cmdblk[7] = (u_char) (cylinders & 0xFF);
+	cmdblk[6] = (u8) (cylinders >> 8) & 0x03;
+	cmdblk[7] = (u8) (cylinders & 0xFF);
 	cmdblk[8] = heads & 0x1F;
-	cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
-	cmdblk[10] = (u_char) (rwrite & 0xFF);
-	cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
-	cmdblk[12] = (u_char) (wprecomp & 0xFF);
+	cmdblk[9] = (u8) (rwrite >> 8) & 0x03;
+	cmdblk[10] = (u8) (rwrite & 0xFF);
+	cmdblk[11] = (u8) (wprecomp >> 8) & 0x03;
+	cmdblk[12] = (u8) (wprecomp & 0xFF);
 	cmdblk[13] = ecc;
 
 	/* Some controllers require geometry info as data, not command */
 
 	if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2))
-		printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
+		printk(KERN_WARNING "xd: error setting characteristics for xd%c\n", 'a'+drive);
 }
 
 
@@ -1145,7 +1153,7 @@
 {
 	devfs_unregister_blkdev(MAJOR_NR, "xd");
 	xd_done();
-	devfs_unregister (devfs_handle);
+	devfs_unregister(devfs_handle);
 	if (xd_drives) {
 		free_irq(xd_irq, NULL);
 		free_dma(xd_dma);
@@ -1171,7 +1179,7 @@
 
 	get_options (str, ARRAY_SIZE (integers), integers);
 	if (integers[0]%3 != 0) {
-		printk("xd: incorrect number of parameters for xd_geo\n");
+		printk(KERN_ERR "xd: incorrect number of parameters for xd_geo\n");
 		return 1;
 	}
 	for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
diff -urN linux-2.4.20-pre2/drivers/block/xd.h linux-2.4.20-pre3/drivers/block/xd.h
--- linux-2.4.20-pre2/drivers/block/xd.h	Wed Aug  9 13:49:29 2000
+++ linux-2.4.20-pre3/drivers/block/xd.h	Sat Aug 17 14:18:46 2002
@@ -80,10 +80,10 @@
 
 /* this structure defines the XT drives and their types */
 typedef struct {
-	u_char heads;
-	u_short cylinders;
-	u_char sectors;
-	u_char control;
+	u8 heads;
+	u16 cylinders;
+	u8 sectors;
+	u8 control;
 } XD_INFO;
 
 /* this structure is returned to the HDIO_GETGEO ioctl */
@@ -99,15 +99,15 @@
 	unsigned int offset;
 	const char *string;
 	void (*init_controller)(unsigned int address);
-	void (*init_drive)(u_char drive);
+	void (*init_drive)(u8 drive);
 	const char *name;
 } XD_SIGNATURE;
 
 #ifndef MODULE
 static int xd_manual_geo_init (char *command);
 #endif /* MODULE */
-static u_char xd_detect (u_char *controller, unsigned int *address);
-static u_char xd_initdrives (void (*init_drive)(u_char drive));
+static u8 xd_detect (u8 *controller, unsigned int *address);
+static u8 xd_initdrives (void (*init_drive)(u8 drive));
 static void xd_geninit (void);
 
 static int xd_open (struct inode *inode,struct file *file);
@@ -115,30 +115,29 @@
 static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
 static int xd_release (struct inode *inode,struct file *file);
 static int xd_reread_partitions (kdev_t dev);
-static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
-static void xd_recalibrate (u_char drive);
+static int xd_readwrite (u8 operation,u8 drive,char *buffer,u_int block,u_int count);
+static void xd_recalibrate (u8 drive);
 
 static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
-static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
-static void xd_wakeup (unsigned long unused);
+static u8 xd_setup_dma (u8 opcode,u8 *buffer,u_int count);
+static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control);
 static void xd_watchdog (unsigned long unused);
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
+static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout);
+static u_int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout);
 
 /* card specific setup and geometry gathering code */
 static void xd_dtc_init_controller (unsigned int address);
-static void xd_dtc5150cx_init_drive (u_char drive);
-static void xd_dtc_init_drive (u_char drive);
+static void xd_dtc5150cx_init_drive (u8 drive);
+static void xd_dtc_init_drive (u8 drive);
 static void xd_wd_init_controller (unsigned int address);
-static void xd_wd_init_drive (u_char drive);
+static void xd_wd_init_drive (u8 drive);
 static void xd_seagate_init_controller (unsigned int address);
-static void xd_seagate_init_drive (u_char drive);
+static void xd_seagate_init_drive (u8 drive);
 static void xd_omti_init_controller (unsigned int address);
-static void xd_omti_init_drive (u_char drive);
+static void xd_omti_init_drive (u8 drive);
 static void xd_xebec_init_controller (unsigned int address);
-static void xd_xebec_init_drive (u_char drive);
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
-static void xd_override_init_drive (u_char drive);
+static void xd_xebec_init_drive (u8 drive);
+static void xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc);
+static void xd_override_init_drive (u8 drive);
 
 #endif /* _LINUX_XD_H */
diff -urN linux-2.4.20-pre2/drivers/cdrom/cdrom.c linux-2.4.20-pre3/drivers/cdrom/cdrom.c
--- linux-2.4.20-pre2/drivers/cdrom/cdrom.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/drivers/cdrom/cdrom.c	Sat Aug 17 14:18:47 2002
@@ -1916,6 +1916,7 @@
 {		
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
+	struct request_sense sense;
 	kdev_t dev = cdi->dev;
 	char buffer[32];
 	int ret = 0;
@@ -1951,9 +1952,11 @@
 		cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
 		if (cgc.buffer == NULL)
 			return -ENOMEM;
+		memset(&sense, 0, sizeof(sense));
+		cgc.sense = &sense;
 		cgc.data_direction = CGC_DATA_READ;
 		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
-		if (ret) {
+		if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) {
 			/*
 			 * SCSI-II devices are not required to support
 			 * READ_CD, so let's try switching block size
diff -urN linux-2.4.20-pre2/drivers/char/agp/agpgart_be.c linux-2.4.20-pre3/drivers/char/agp/agpgart_be.c
--- linux-2.4.20-pre2/drivers/char/agp/agpgart_be.c	Sat Aug 17 14:18:16 2002
+++ linux-2.4.20-pre3/drivers/char/agp/agpgart_be.c	Sat Aug 17 14:18:47 2002
@@ -497,6 +497,7 @@
 	int i;
 	void *temp;
 	struct page *page;
+	int err = 0;
 
 	/* The generic routines can't handle 2 level gatt's */
 	if (agp_bridge.size_type == LVL2_APER_SIZE) {
@@ -561,6 +562,7 @@
 					    agp_bridge.current_size;
 					break;
 				}
+				temp = agp_bridge.current_size;
 			} else {
 				agp_bridge.aperture_size_idx = i;
 			}
@@ -582,12 +584,15 @@
 		SetPageReserved(page);
 
 	agp_bridge.gatt_table_real = (unsigned long *) table;
-	CACHE_FLUSH();
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(table), 1<<page_order, PAGE_KERNEL_NOCACHE);
+#endif
+	if (!err) 
 	agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
 					(PAGE_SIZE * (1 << page_order)));
 	CACHE_FLUSH();
 
-	if (agp_bridge.gatt_table == NULL) {
+	if (agp_bridge.gatt_table == NULL || err) {
 		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 			ClearPageReserved(page);
 
@@ -651,6 +656,10 @@
 	 * from the table.
 	 */
 
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(agp_bridge.gatt_table_real), 1<<page_order, 
+			 PAGE_KERNEL);
+#endif
 	iounmap(agp_bridge.gatt_table);
 	table = (char *) agp_bridge.gatt_table_real;
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
@@ -769,6 +778,12 @@
 	if (page == NULL) {
 		return 0;
 	}
+#ifdef CONFIG_X86
+	if (change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) < 0) {
+		__free_page(page); 
+		return 0;
+	}
+#endif
 	get_page(page);
 	LockPage(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
@@ -785,6 +800,9 @@
 	}
 	
 	page = virt_to_page(pt);
+#ifdef CONFIG_X86
+	change_page_attr(page, 1, PAGE_KERNEL); 
+#endif	
 	put_page(page);
 	UnlockPage(page);
 	free_page((unsigned long) pt);
@@ -2318,6 +2336,7 @@
 static int amd_create_page_map(amd_page_map *page_map)
 {
 	int i;
+	int err = 0;
 
 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
 	if (page_map->real == NULL) {
@@ -2325,9 +2344,13 @@
 	}
 	SetPageReserved(virt_to_page(page_map->real));
 	CACHE_FLUSH();
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL_NOCACHE);
+#endif
+	if (!err) 
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
-	if (page_map->remapped == NULL) {
+	if (page_map->remapped == NULL || err) {
 		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
@@ -2345,6 +2368,9 @@
 static void amd_free_page_map(amd_page_map *page_map)
 {
 	iounmap(page_map->remapped);
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL);
+#endif
 	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
 }
@@ -2824,36 +2850,31 @@
 	}
 }
 
+
 static unsigned long ali_alloc_page(void)
 {
-	struct page *page;
-	u32 temp;
-
-	page = alloc_page(GFP_KERNEL);
-	if (page == NULL)
+	unsigned long p = agp_generic_alloc_page(); 
+	if (!p) 
 		return 0;
 
-	get_page(page);
-	LockPage(page);
-	atomic_inc(&agp_bridge.current_memory_agp);
-
+	/* probably not needed anymore */
 	global_cache_flush();
 
 	if (agp_bridge.type == ALI_M1541) {
+		u32 temp;
 		pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
 		pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
 				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys(page_address(page))) |
+				  virt_to_phys((void *)p)) |
 				    ALI_CACHE_FLUSH_EN ));
 	}
-	return (unsigned long)page_address(page);
+	return p;
 }
 
 static void ali_destroy_page(unsigned long addr)
 {
 	u32 temp;
 	void *pt = (void *) addr;
-	struct page *page;
 
 	if (pt == NULL)
 		return;
@@ -2864,15 +2885,11 @@
 		pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
 		pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
 				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys((void *)pt)) |
+				  virt_to_phys(pt)) |
 				    ALI_CACHE_FLUSH_EN));
 	}
 
-	page = virt_to_page(pt);
-	put_page(page);
-	UnlockPage(page);
-	free_page((unsigned long) pt);
-	atomic_dec(&agp_bridge.current_memory_agp);
+	agp_generic_destroy_page(addr);
 }
 
 /* Setup function */
@@ -2947,16 +2964,21 @@
 static int serverworks_create_page_map(serverworks_page_map *page_map)
 {
 	int i;
+	int err = 0;
 
 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
 	if (page_map->real == NULL) {
 		return -ENOMEM;
 	}
 	SetPageReserved(virt_to_page(page_map->real));
+#ifdef CONFIG_X86
+	err = change_page_attr(virt_to_page(page_map->real), 1, PAGE_KERNEL_NOCACHE);
+#endif
 	CACHE_FLUSH();
+	if (!err) 
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
-	if (page_map->remapped == NULL) {
+	if (page_map->remapped == NULL || err) {
 		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
@@ -2973,6 +2995,9 @@
 
 static void serverworks_free_page_map(serverworks_page_map *page_map)
 {
+#ifdef CONFIG_X86
+	change_page_attr(virt_to_page(page_map->real),1,PAGE_KERNEL); 
+#endif
 	iounmap(page_map->remapped);
 	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
diff -urN linux-2.4.20-pre2/drivers/char/drm-4.0/ffb_drv.c linux-2.4.20-pre3/drivers/char/drm-4.0/ffb_drv.c
--- linux-2.4.20-pre2/drivers/char/drm-4.0/ffb_drv.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.20-pre3/drivers/char/drm-4.0/ffb_drv.c	Sat Aug 17 14:18:47 2002
@@ -710,8 +710,7 @@
 		/* Contention */
 		atomic_inc(&dev->total_sleeps);
 		current->state = TASK_INTERRUPTIBLE;
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		if (signal_pending(current)) {
 			ret = -ERESTARTSYS;
 			break;
diff -urN linux-2.4.20-pre2/drivers/char/drm-4.0/tdfx_drv.c linux-2.4.20-pre3/drivers/char/drm-4.0/tdfx_drv.c
--- linux-2.4.20-pre2/drivers/char/drm-4.0/tdfx_drv.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.20-pre3/drivers/char/drm-4.0/tdfx_drv.c	Sat Aug 17 14:18:47 2002
@@ -578,10 +578,7 @@
 
                                 /* Contention */
                         atomic_inc(&dev->total_sleeps);
-#if 1
-			current->policy |= SCHED_YIELD;
-#endif
-                        schedule();
+			yield();
                         if (signal_pending(current)) {
                                 ret = -ERESTARTSYS;
                                 break;
@@ -604,8 +601,7 @@
                    when dev->last_context == lock.context
                    NOTE WE HOLD THE LOCK THROUGHOUT THIS
                    TIME! */
-		current->policy |= SCHED_YIELD;
-	        schedule();
+		yield();
 	        current->state = TASK_RUNNING;
 	        remove_wait_queue(&dev->context_wait, &entry);
 	        if (signal_pending(current)) {
diff -urN linux-2.4.20-pre2/drivers/char/i810-tco.c linux-2.4.20-pre3/drivers/char/i810-tco.c
--- linux-2.4.20-pre2/drivers/char/i810-tco.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/drivers/char/i810-tco.c	Sat Aug 17 14:18:47 2002
@@ -223,7 +223,10 @@
 
 		/* scan to see wether or not we got the magic character */
 		for (i = 0; i != len; i++) {
-			if (data[i] == 'V')
+			u8 c;
+			if(get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
 				tco_expect_close = 42;
 		}
 
diff -urN linux-2.4.20-pre2/drivers/char/isicom.c linux-2.4.20-pre3/drivers/char/isicom.c
--- linux-2.4.20-pre2/drivers/char/isicom.c	Sat Aug 17 14:18:16 2002
+++ linux-2.4.20-pre3/drivers/char/isicom.c	Fri Aug  2 17:39:43 2002
@@ -1255,11 +1255,7 @@
 			   created more space in xmit_buf when the ctrl 
 			   gets back here  */
 			sti(); 
-			if (copy_from_user(tmp_buf, buf, cnt)) {
-				up(&tmp_buf_sem);
-				restore_flags(flags);
-				return -EFAULT;
-			}
+			copy_from_user(tmp_buf, buf, cnt);
 			cli();
 			cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
 			SERIAL_XMIT_SIZE - port->xmit_head));
diff -urN linux-2.4.20-pre2/drivers/char/joystick/analog.c linux-2.4.20-pre3/drivers/char/joystick/analog.c
--- linux-2.4.20-pre2/drivers/char/joystick/analog.c	Thu Oct 25 14:01:51 2001
+++ linux-2.4.20-pre3/drivers/char/joystick/analog.c	Sat Aug 17 14:18:47 2002
@@ -137,10 +137,9 @@
  */
 
 #ifdef __i386__
-#define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
-#define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
-#define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
+#define GET_TIME(x)	do { if (cpu_has_tsc) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
+#define DELTA(x,y)	(cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
+#define TIME_NAME	(cpu_has_tsc?"TSC":"PIT")
 #elif __x86_64__
 #define GET_TIME(x)	rdtscl(x)
 #define DELTA(x,y)	((y)-(x))
diff -urN linux-2.4.20-pre2/drivers/char/random.c linux-2.4.20-pre3/drivers/char/random.c
--- linux-2.4.20-pre2/drivers/char/random.c	Fri Nov  9 14:01:21 2001
+++ linux-2.4.20-pre3/drivers/char/random.c	Sat Aug 17 14:18:47 2002
@@ -412,13 +412,13 @@
  * deal with a variable rotate of x bits.  So we use a bit of asm magic.
  */
 #if (!defined (__i386__))
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	return (word << i) | (word >> (32 - i));
 	
 }
 #else
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	__asm__("roll %%cl,%0"
 		:"=r" (word)
@@ -735,7 +735,7 @@
 	int		entropy = 0;
 
 #if defined (__i386__)
-	if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) {
+	if (cpu_has_tsc) {
 		__u32 high;
 		rdtsc(time, high);
 		num ^= high;
@@ -1643,7 +1643,7 @@
 			return -EINVAL;
 		if (size > random_state->poolinfo.poolwords)
 			size = random_state->poolinfo.poolwords;
-		if (copy_to_user(p, random_state->pool, size * 4))
+		if (copy_to_user(p, random_state->pool, size * sizeof(__u32)))
 			return -EFAULT;
 		return 0;
 	case RNDADDENTROPY:
diff -urN linux-2.4.20-pre2/drivers/char/sonypi.h linux-2.4.20-pre3/drivers/char/sonypi.h
--- linux-2.4.20-pre2/drivers/char/sonypi.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre3/drivers/char/sonypi.h	Sat Aug 17 14:18:47 2002
@@ -214,6 +214,7 @@
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
 	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
 	{ 0x00, 0x00 }
 };
 
@@ -258,7 +259,7 @@
 	while (--n && (command)) \
 		udelay(1); \
 	if (!n && (verbose || !quiet)) \
-		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : " __FUNCTION__ "(line %d)\n", __LINE__); \
+		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \
 }
 
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre2/drivers/char/vt.c linux-2.4.20-pre3/drivers/char/vt.c
--- linux-2.4.20-pre2/drivers/char/vt.c	Fri Nov 16 10:08:28 2001
+++ linux-2.4.20-pre3/drivers/char/vt.c	Sat Aug 17 14:18:47 2002
@@ -481,7 +481,7 @@
 		ucval = keyboard_type;
 		goto setchar;
 
-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
+#if defined(__i386__) || defined(__mc68000__) || defined(__ppc__) || defined(__sparc__)
 		/*
 		 * These cannot be implemented on any machine that implements
 		 * ioperm() in user level (such as Alpha PCs).
diff -urN linux-2.4.20-pre2/drivers/hotplug/cpqphp_nvram.c linux-2.4.20-pre3/drivers/hotplug/cpqphp_nvram.c
--- linux-2.4.20-pre2/drivers/hotplug/cpqphp_nvram.c	Fri Nov  9 14:01:22 2001
+++ linux-2.4.20-pre3/drivers/hotplug/cpqphp_nvram.c	Sat Aug 17 14:18:47 2002
@@ -176,12 +176,12 @@
 	
 	spin_lock_irqsave(&int15_lock, flags);
 	__asm__ (
-		"xorl   %%ebx,%%ebx
-		xorl    %%edx,%%edx
-		pushf
-		push    %%cs
-		cli
-		call    *%6"
+		"xorl   %%ebx,%%ebx \n"
+		"xorl   %%edx,%%edx \n"
+		"pushf              \n"
+		"push    %%cs       \n"
+		"cli                \n"
+		"call    *%6        \n"
 		: "=c" (*buf_size), "=a" (ret_val)
 		: "a" (op), "c" (*buf_size), "S" (ev_name),
 		"D" (buffer), "m" (compaq_int15_entry_point)
diff -urN linux-2.4.20-pre2/drivers/ide/ataraid.c linux-2.4.20-pre3/drivers/ide/ataraid.c
--- linux-2.4.20-pre2/drivers/ide/ataraid.c	Thu Oct 25 13:58:35 2001
+++ linux-2.4.20-pre3/drivers/ide/ataraid.c	Sat Aug 17 14:18:47 2002
@@ -121,11 +121,8 @@
 	void *ptr = NULL;
 	while (!ptr) {
 		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr) {
-			__set_current_state(TASK_RUNNING);
-	                current->policy |= SCHED_YIELD;
-	                schedule();             
-		}
+		if (!ptr)
+			yield();
 	}
 	return ptr;
 }
@@ -137,11 +134,8 @@
 	void *ptr = NULL;
 	while (!ptr) {
 		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr) {
-			__set_current_state(TASK_RUNNING);
-	                current->policy |= SCHED_YIELD;
-	                schedule();             
-		}
+		if (!ptr)
+			yield();
 	}
 	return ptr;
 }
diff -urN linux-2.4.20-pre2/drivers/isdn/Config.in linux-2.4.20-pre3/drivers/isdn/Config.in
--- linux-2.4.20-pre2/drivers/isdn/Config.in	Sat Aug 17 14:18:17 2002
+++ linux-2.4.20-pre3/drivers/isdn/Config.in	Sat Aug 17 14:18:48 2002
@@ -77,6 +77,7 @@
    bool '  HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 #      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      bool '  Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
 	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/Makefile linux-2.4.20-pre3/drivers/isdn/hisax/Makefile
--- linux-2.4.20-pre2/drivers/isdn/hisax/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/isdn/hisax/Makefile	Sat Aug 17 14:18:48 2002
@@ -34,7 +34,7 @@
 hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
 hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
-hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
 hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
 hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
@@ -52,6 +52,7 @@
 hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
+hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
 #hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
 
 hisax-objs += $(sort $(hisax-objs-y))
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/amd7930_fn.c linux-2.4.20-pre3/drivers/isdn/hisax/amd7930_fn.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/amd7930_fn.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/amd7930_fn.c	Sat Aug 17 14:18:48 2002
@@ -0,0 +1,761 @@
+/* gerdes_amd7930.c,v 0.99 2001/10/02
+ *
+ * gerdes_amd7930.c     Amd 79C30A and 79C32A specific routines
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ *
+ * Notes:
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ *
+ * Please don't report any malfunction to me without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary this driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+#include "amd7930_fn.h"
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+static void Amd7930_new_ph(struct IsdnCardState *cs);
+
+
+void /* macro wWordAMD */
+WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
+{
+        wByteAMD(cs, 0x00, reg);
+        wByteAMD(cs, 0x01, LOBYTE(val));
+        wByteAMD(cs, 0x01, HIBYTE(val));
+}
+
+WORD /* macro rWordAMD */
+ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
+{
+        WORD res;
+        /* direct access register */
+        if(reg < 8) {
+        	res = rByteAMD(cs, reg);
+                res += 256*rByteAMD(cs, reg);
+        }
+        /* indirect access register */
+        else {
+                wByteAMD(cs, 0x00, reg);
+	        res = rByteAMD(cs, 0x01);
+                res += 256*rByteAMD(cs, 0x01);
+        }
+	return (res);
+}
+
+
+static void
+Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
+{
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
+
+        cs->dc.amd7930.lmr1 = command;
+        wByteAMD(cs, 0xA3, command);
+}
+
+
+
+static BYTE i430States[] = {
+// to   reset  F3    F4    F5    F6    F7    F8    AR     from
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04,   // F3
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F4
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F5
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00,   // F6
+        0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00,   // F7
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,   // F8
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A};  // AR
+
+
+/*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
+static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+
+
+
+
+static void
+Amd7930_get_state(struct IsdnCardState *cs) {
+        BYTE lsr = rByteAMD(cs, 0xA1);
+        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+        Amd7930_new_ph(cs);
+}
+
+
+
+static void
+Amd7930_new_ph(struct IsdnCardState *cs)
+{
+        u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
+        u_char message = i430States[index];
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
+                        cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
+
+        cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
+
+        /* abort transmit if nessesary */
+        if ((message & 0xf0) && (cs->tx_skb)) {
+                wByteAMD(cs, 0x21, 0xC2);
+                wByteAMD(cs, 0x21, 0x02);
+        }
+
+	switch (message & 0x0f) {
+
+                case (1):
+                        l1_msg(cs, HW_RESET | INDICATION, NULL);
+                        Amd7930_get_state(cs);
+                        break;
+                case (2): /* init, Card starts in F3 */
+                        l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+                        break;
+                case (3):
+                        l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                        break;
+                case (4):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
+                        break;
+                case (5):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                        break;
+                case (6):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (7): /* init, Card starts in F7 */
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (8):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        /* fall through */
+                case (9):
+                        Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (10):
+                        Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
+                        cs->dc.amd7930.old_state = 3;
+                        break;
+                case (11):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                        break;
+		default:
+			break;
+	}
+}
+
+
+
+static void
+Amd7930_bh(struct IsdnCardState *cs)
+{
+
+        struct PStack *stptr;
+
+	if (!cs)
+		return;
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+                if (cs->debug)
+			debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
+		stptr = cs->stlist;
+		while (stptr != NULL) {
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr = stptr->next;
+		}
+	}
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
+                Amd7930_new_ph(cs);
+        }
+
+        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
+                DChannel_proc_rcv(cs);
+        }
+
+        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
+                DChannel_proc_xmt(cs);
+        }
+}
+
+
+void
+Amd7930_sched_event(struct IsdnCardState *cs, int event) // ok
+{
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "AMD7930: sched_event 0x%X", event);
+        }
+
+        test_and_set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
+{
+
+        BYTE stat, der;
+	BYTE *ptr;
+	struct sk_buff *skb;
+
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: empty_Dfifo");
+
+
+	ptr = cs->rcvbuf + cs->rcvidx;
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+	/* read D-Channel-Fifo*/
+	stat = rByteAMD(cs, 0x07); // DSR2
+
+		/* while Data in Fifo ... */
+		while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
+			*ptr = rByteAMD(cs, 0x04); // DCRB
+			ptr++;
+	                stat = rByteAMD(cs, 0x07); // DSR2
+			cs->rcvidx = ptr - cs->rcvbuf;
+
+                        /* Paket ready? */
+			if (stat & 1) {
+
+                                der = rWordAMD(cs, 0x03);
+
+                                /* no errors, packet ok */
+                                if(!der && !flag) {
+					rWordAMD(cs, 0x89); // clear DRCR
+
+                                        if ((cs->rcvidx) > 0) {
+                                                if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
+							printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
+						else {
+                                                        /* Debugging */
+                                                        if (cs->debug & L1_DEB_ISAC_FIFO) {
+								char *t = cs->dlog;
+
+								t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
+								QuickHex(t, cs->rcvbuf, cs->rcvidx);
+								debugl1(cs, cs->dlog);
+							}
+                                                        /* moves recieved data in sk-buffer */
+							memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
+							skb_queue_tail(&cs->rq, skb);
+						}
+					}
+
+				}
+                                /* throw damaged packets away, reset recieve-buffer, indicate RX */
+				ptr = cs->rcvbuf;
+				cs->rcvidx = 0;
+				Amd7930_sched_event(cs, D_RCVBUFREADY);
+			}
+                }
+		/* Packet to long, overflow */
+		if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
+			if (cs->debug & L1_DEB_WARN)
+			        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
+			cs->rcvidx = 0;
+			return;
+		}
+	/* AMD interrupts on */
+	AmdIrqOn(cs);
+}
+
+
+static void
+Amd7930_fill_Dfifo(struct IsdnCardState *cs)
+{
+
+        WORD dtcrr, dtcrw, len, count;
+        BYTE txstat, dmr3;
+        BYTE *ptr, *deb_ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: fill_Dfifo");
+
+	if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
+		return;
+
+        dtcrw = 0;
+        if(!cs->dc.amd7930.tx_xmtlen)
+                /* new Frame */
+                len = dtcrw = cs->tx_skb->len;
+        /* continue frame */
+        else len = cs->dc.amd7930.tx_xmtlen;
+
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+        deb_ptr = ptr = cs->tx_skb->data;
+
+        /* while free place in tx-fifo available and data in sk-buffer */
+        txstat = 0x10;
+        while((txstat & 0x10) && (cs->tx_cnt < len)) {
+                wByteAMD(cs, 0x04, *ptr);
+                ptr++;
+                cs->tx_cnt++;
+                txstat= rByteAMD(cs, 0x07);
+        }
+        count = ptr - cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+
+
+        dtcrr = rWordAMD(cs, 0x85); // DTCR
+        dmr3  = rByteAMD(cs, 0x8E);
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
+        }
+
+        /* writeing of dtcrw starts transmit */
+        if(!cs->dc.amd7930.tx_xmtlen) {
+                wWordAMD(cs, 0x85, dtcrw);
+                cs->dc.amd7930.tx_xmtlen = dtcrw;
+        }
+
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
+	add_timer(&cs->dbusytimer);
+
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
+		QuickHex(t, deb_ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+	/* AMD interrupts on */
+        AmdIrqOn(cs);
+}
+
+
+void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
+{
+	BYTE dsr1, dsr2, lsr;
+        WORD der;
+
+ while (irflags)
+ {
+
+        dsr1 = rByteAMD(cs, 0x02);
+        der  = rWordAMD(cs, 0x03);
+        dsr2 = rByteAMD(cs, 0x07);
+        lsr  = rByteAMD(cs, 0xA1);
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
+
+        /* D error -> read DER and DSR2 bit 2 */
+	if (der || (dsr2 & 4)) {
+
+                if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
+
+                /* RX, TX abort if collision detected */
+                if (der & 2) {
+                        wByteAMD(cs, 0x21, 0xC2);
+                        wByteAMD(cs, 0x21, 0x02);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+                        /* restart frame */
+                        if (cs->tx_skb) {
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+				Amd7930_fill_Dfifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
+				debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
+			}
+                }
+                /* remove damaged data from fifo */
+		Amd7930_empty_Dfifo(cs, 1);
+
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+                /* restart TX-Frame */
+                if (cs->tx_skb) {
+			skb_push(cs->tx_skb, cs->tx_cnt);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen = 0;
+			Amd7930_fill_Dfifo(cs);
+		}
+	}
+
+        /* D TX FIFO empty -> fill */
+	if (irflags & 1) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
+
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len)
+				Amd7930_fill_Dfifo(cs);
+		}
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+
+        /* D RX FIFO full or tiny packet in Fifo -> empty */
+	if ((irflags & 2) || (dsr1 & 2)) {
+                if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
+                Amd7930_empty_Dfifo(cs, 0);
+	}
+
+
+        /* D-Frame transmit complete */
+	if (dsr1 & 64) {
+		if (cs->debug & L1_DEB_ISAC) {
+			debugl1(cs, "Amd7930: interrupt: transmit packet ready");
+        	}
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+
+                if (cs->tx_skb) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
+                        dev_kfree_skb_irq(cs->tx_skb);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			cs->tx_skb = NULL;
+                }
+                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
+	        	cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			Amd7930_fill_Dfifo(cs);
+		}
+                else
+			Amd7930_sched_event(cs, D_XMTBUFREADY);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+        }
+
+	/* LIU status interrupt -> read LSR, check statechanges */
+	if (lsr & 0x38) {
+                /* AMD interrupts off */
+                AmdIrqOff(cs);
+
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
+
+		cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+
+		Amd7930_sched_event(cs, D_L1STATECHANGE);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+        /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
+        irflags = rByteAMD(cs, 0x00);
+ }
+
+}
+
+static void
+Amd7930_l1hw(struct PStack *st, int pr, void *arg)
+{
+        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+                        if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
+#endif
+				Amd7930_fill_Dfifo(cs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
+#endif
+			Amd7930_fill_Dfifo(cs);
+			break;
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (HW_RESET | REQUEST):
+
+                        if ((cs->dc.amd7930.ph_state == 8))
+                                /* b-channels off, PH-AR cleared
+                                 * change to F3 */
+                                Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
+			else {
+                                Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
+                                cs->dc.amd7930.ph_state = 2;
+                                Amd7930_new_ph(cs);
+                        }
+			break;
+		case (HW_ENABLE | REQUEST):
+                        cs->dc.amd7930.ph_state = 9;
+                        Amd7930_new_ph(cs);
+			break;
+		case (HW_INFO3 | REQUEST):
+			// automatic
+			break;
+		case (HW_TESTLOOP | REQUEST):
+			/* not implemented yet */
+			break;
+		case (HW_DEACTIVATE | RESPONSE):
+                        skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+			break;
+		default:
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
+			break;
+	}
+}
+
+void
+setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
+{
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: setstack called");
+
+        st->l1.l1hw = Amd7930_l1hw;
+}
+
+
+void
+DC_Close_Amd7930(struct IsdnCardState *cs) {
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: DC_Close called");
+}
+
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *stptr;
+        WORD dtcr, der;
+        BYTE dsr1, dsr2;
+
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer expired!");
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+                /* D Transmit Byte Count Register:
+                 * Counts down packet's number of Bytes, 0 if packet ready */
+                dtcr = rWordAMD(cs, 0x85);
+                dsr1 = rByteAMD(cs, 0x02);
+                dsr2 = rByteAMD(cs, 0x07);
+                der  = rWordAMD(cs, 0x03);
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
+
+		if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {	/* D-Channel Busy */
+			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+			stptr = cs->stlist;
+			while (stptr != NULL) {
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr = stptr->next;
+			}
+
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
+				debugl1(cs, "Amd7930: D-Channel Busy no skb");
+
+			}
+			/* Transmitter reset, abort transmit */
+			wByteAMD(cs, 0x21, 0x82);
+			wByteAMD(cs, 0x21, 0x02);
+			cs->irq_func(cs->irq, cs, NULL);
+
+                        if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
+		}
+	}
+}
+
+
+
+void __devinit
+Amd7930_init(struct IsdnCardState *cs)
+{
+    WORD *ptr;
+    BYTE cmd, cnt;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: initamd called");
+
+        cs->dc.amd7930.tx_xmtlen = 0;
+        cs->dc.amd7930.old_state = 0;
+        cs->dc.amd7930.lmr1 = 0x40;
+        cs->dc.amd7930.ph_command = Amd7930_ph_command;
+        cs->tqueue.routine = (void *) (void *) Amd7930_bh;
+	cs->setstack_d = setstack_Amd7930;
+	cs->DC_Close = DC_Close_Amd7930;
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+	/* AMD Initialisation */
+	for (ptr = initAMD; *ptr != 0xFFFF; ) {
+		cmd = LOBYTE(*ptr);
+
+                /* read */
+                if (*ptr++ >= 0x100) {
+			if (cmd < 8)
+                                /* setzt Register zurück */
+                                rByteAMD(cs, cmd);
+			else {
+				wByteAMD(cs, 0x00, cmd);
+				for (cnt = *ptr++; cnt > 0; cnt--)
+					rByteAMD(cs, 0x01);
+			}
+		}
+                /* write */
+                else if (cmd < 8)
+			wByteAMD(cs, cmd, LOBYTE(*ptr++));
+
+		else {
+			wByteAMD(cs, 0x00, cmd);
+			for (cnt = *ptr++; cnt > 0; cnt--)
+				wByteAMD(cs, 0x01, LOBYTE(*ptr++));
+		}
+	}
+}
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/amd7930_fn.h linux-2.4.20-pre3/drivers/isdn/hisax/amd7930_fn.h
--- linux-2.4.20-pre2/drivers/isdn/hisax/amd7930_fn.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/amd7930_fn.h	Sat Aug 17 14:18:48 2002
@@ -0,0 +1,69 @@
+/* 2001/10/02
+ *
+ * gerdes_amd7930.h     Header-file included by
+ *                      gerdes_amd7930.c
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define rByteAMD(cs, reg)					cs->readisac(cs, reg)
+#define wByteAMD(cs, reg, val)					cs->writeisac(cs, reg, val)
+#define rWordAMD(cs, reg)					ReadWordAmd7930(cs, reg)
+#define wWordAMD(cs, reg, val)					WriteWordAmd7930(cs, reg, val)
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+
+#define AmdIrqOff(cs)						cs->dc.amd7930.setIrqMask(cs, 0)
+#define AmdIrqOn(cs)						cs->dc.amd7930.setIrqMask(cs, 1)
+
+#define AMD_CR		0x00
+#define AMD_DR		0x01
+
+
+#define DBUSY_TIMER_VALUE 80
+
+static WORD initAMD[] = {
+	0x0100,
+
+	0x00A5, 3, 0x01, 0x40, 0x58,				// LPR, LMR1, LMR2
+	0x0086, 1, 0x0B,					// DMR1 (D-Buffer TH-Interrupts on)
+	0x0087, 1, 0xFF,					// DMR2
+	0x0092, 1, 0x03,					// EFCR (extended mode d-channel-fifo on)
+	0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,			// FRAR4, SRAR4, DMR3, DMR4 (address recognition )
+	0x0084, 2, 0x80, 0x00,					// DRLR
+	0x00C0, 1, 0x47,					// PPCR1
+	0x00C8, 1, 0x01,					// PPCR2
+
+	0x0102,
+	0x0107,
+	0x01A1, 1,
+	0x0121, 1,
+	0x0189, 2,
+
+	0x0045, 4, 0x61, 0x72, 0x00, 0x00,			// MCR1, MCR2, MCR3, MCR4
+	0x0063, 2, 0x08, 0x08,					// GX
+	0x0064, 2, 0x08, 0x08,					// GR
+	0x0065, 2, 0x99, 0x00,					// GER
+	0x0066, 2, 0x7C, 0x8B,					// STG
+	0x0067, 2, 0x00, 0x00,					// FTGR1, FTGR2
+	0x0068, 2, 0x20, 0x20,					// ATGR1, ATGR2
+	0x0069, 1, 0x4F,					// MMR1
+	0x006A, 1, 0x00,					// MMR2
+	0x006C, 1, 0x40,					// MMR3
+	0x0021, 1, 0x02,					// INIT
+	0x00A3, 1, 0x40,					// LMR1
+
+	0xFFFF};
+
+extern void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags);
+extern void Amd7930_init(struct IsdnCardState *cs);
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/asuscom.c linux-2.4.20-pre3/drivers/isdn/hisax/asuscom.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/asuscom.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/asuscom.c	Sat Aug 17 14:18:48 2002
@@ -14,6 +14,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -309,6 +310,27 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id asus_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), 
+	  (unsigned long) "Asus1688 PnP" },
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), 
+	  (unsigned long) "Asus1690 PnP" },
+	{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
+	  ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), 
+	  (unsigned long) "Isurf2 PnP" },
+	{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
+	  ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), 
+	  (unsigned long) "Iscas TE320" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *adev = &asus_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_asuscom(struct IsdnCard *card)
 {
@@ -321,7 +343,45 @@
 	printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_ASUSCOM)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(adev->card_vendor) {
+			if ((pb = isapnp_find_card(adev->card_vendor,
+				adev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					adev->vendor, adev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)adev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
+				}
+			}
+			adev++;
+			pnp_c=NULL;
+		} 
+		if (!adev->card_vendor) {
+			printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	bytecnt = 8;
 	cs->hw.asus.cfg_reg = card->para[1];
 	cs->irq = card->para[0];
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/avm_pci.c linux-2.4.20-pre3/drivers/isdn/hisax/avm_pci.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/avm_pci.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/avm_pci.c	Sat Aug 17 14:18:48 2002
@@ -19,6 +19,7 @@
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
@@ -763,6 +764,10 @@
 }
 
 static struct pci_dev *dev_avm __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *bus_avm __initdata = NULL;
+static struct pci_dev *pnp_avm __initdata = NULL;
+#endif
 
 int __init
 setup_avm_pcipnp(struct IsdnCard *card)
@@ -776,10 +781,47 @@
 	if (cs->typ != ISDN_CTYPE_FRITZPCI)
 		return (0);
 	if (card->para[1]) {
+		/* old manual method */
 		cs->hw.avm.cfg_reg = card->para[1];
 		cs->irq = card->para[0];
 		cs->subtyp = AVM_FRITZ_PNP;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *ba;
+			if ((ba = isapnp_find_card(
+				ISAPNP_VENDOR('A', 'V', 'M'),
+				ISAPNP_FUNCTION(0x0900), bus_avm))) {
+				bus_avm = ba;
+				pnp_avm = NULL;
+				if ((pnp_avm = isapnp_find_dev(bus_avm,
+					ISAPNP_VENDOR('A', 'V', 'M'),
+					ISAPNP_FUNCTION(0x0900), pnp_avm))) {
+					pnp_avm->prepare(pnp_avm);
+					pnp_avm->deactivate(pnp_avm);
+					pnp_avm->activate(pnp_avm);
+					cs->hw.avm.cfg_reg =
+						pnp_avm->resource[0].start;
+					cs->irq = 
+						pnp_avm->irq_resource[0].start;
+					if (!cs->irq) {
+						printk(KERN_ERR "FritzPnP:No IRQ\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					if (!cs->hw.avm.cfg_reg) {
+						printk(KERN_ERR "FritzPnP:No IO address\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					cs->subtyp = AVM_FRITZ_PNP;
+					goto ready;
+				}
+			}
+		} else {
+			printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "FritzPCI: no PCI bus present\n");
@@ -810,6 +852,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}
+ready:
 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
 	if (check_region((cs->hw.avm.cfg_reg), 32)) {
 		printk(KERN_WARNING
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/config.c linux-2.4.20-pre3/drivers/isdn/hisax/config.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/config.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/isdn/hisax/config.c	Sat Aug 17 14:18:48 2002
@@ -75,6 +75,8 @@
  *   37 HFC 2BDS0 S+/SP         p0=irq p1=iobase
  *   38 Travers Technologies NETspider-U PCI card
  *   39 HFC 2BDS0-SP PCMCIA     p0=irq p1=iobase
+ *   40 hotplug interface
+ *   41 Formula-n enter:now ISDN PCI a/b   none
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
@@ -93,6 +95,7 @@
 	"Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
 	"Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
 	"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+	"Hotplug", "Formula-n enter:now PCI a/b", 
 };
 
 void HiSax_closecard(int cardnr);
@@ -601,6 +604,10 @@
 extern int setup_netjet_u(struct IsdnCard *card);
 #endif
 
+#if CARD_FN_ENTERNOW_PCI
+extern int setup_enternow_pci(struct IsdnCard *card);
+#endif
+
 /*
  * Find card with given driverId
  */
@@ -1136,6 +1143,11 @@
 		ret = setup_netjet_u(card);
 		break;
 #endif
+#if CARD_FN_ENTERNOW_PCI
+	case ISDN_CTYPE_ENTERNOW:
+		ret = setup_enternow_pci(card);
+		break;
+#endif
 	case ISDN_CTYPE_DYNAMIC:
 		ret = 2;
 		break;
@@ -2092,6 +2104,9 @@
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20,     PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20_U,   PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA201,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
+	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA202,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
 #endif
 #ifdef CONFIG_HISAX_ELSA
 	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK,   PCI_ANY_ID, PCI_ANY_ID},
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/diva.c linux-2.4.20-pre3/drivers/isdn/hisax/diva.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/diva.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/diva.c	Sat Aug 17 14:18:48 2002
@@ -22,8 +22,12 @@
 #include "isac.h"
 #include "hscx.h"
 #include "ipac.h"
+//##################################
+#include "ipacx.h"
+//##################################
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -49,6 +53,9 @@
 #define DIVA_PCI	2
 #define DIVA_IPAC_ISA	3
 #define DIVA_IPAC_PCI	4
+//##################################
+#define DIVA_IPACX_PCI	5
+//##################################
 
 /* CTRL (Read) */
 #define DIVA_IRQ_STAT	0x01
@@ -68,10 +75,16 @@
 #define PITA_MISC_REG		0x1c
 #ifdef __BIG_ENDIAN
 #define PITA_PARA_SOFTRESET	0x00000001
+//################################################
+#define PITA_SER_SOFTRESET	0x00000002
+//################################################
 #define PITA_PARA_MPX_MODE	0x00000004
 #define PITA_INT0_ENABLE	0x00000200
 #else
 #define PITA_PARA_SOFTRESET	0x01000000
+//################################################
+#define PITA_SER_SOFTRESET	0x02000000
+//################################################
 #define PITA_PARA_MPX_MODE	0x04000000
 #define PITA_INT0_ENABLE	0x00020000
 #endif
@@ -239,6 +252,49 @@
 	memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
 }
 
+//######################################################################
+/* IO-Functions for IPACX type cards */
+static u_char
+MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
+{
+	return (memreadreg(cs->hw.diva.cfg_reg, offset));
+}
+
+static void
+MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset, value);
+}
+
+static void
+MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		*data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
+}
+
+static void
+MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
+}
+
+static u_char
+MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return(memreadreg(cs->hw.diva.cfg_reg, offset + 
+                    (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
+}
+
+static void
+MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset + 
+              (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
+}
+//######################################################################
+
 /*
  * fast interrupt HSCX stuff goes here
  */
@@ -549,7 +605,7 @@
 	u_char exval;
 	struct BCState *bcs;
 
-	if (val & 0x01) {
+	if (val & 0x01) { // EXB
 		bcs = cs->bcs + 1;
 		exval = MemReadHSCX(cs, 1, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -576,7 +632,7 @@
 			debugl1(cs, "HSCX B interrupt %x", val);
 		Memhscx_interrupt(cs, val, 1);
 	}
-	if (val & 0x02) {
+	if (val & 0x02) {	// EXA
 		bcs = cs->bcs;
 		exval = MemReadHSCX(cs, 0, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -598,7 +654,7 @@
 		} else if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A EXIR %x", exval);
 	}
-	if (val & 0x04) {
+	if (val & 0x04) {	// ICA
 		exval = MemReadHSCX(cs, 0, HSCX_ISTA);
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A interrupt %x", exval);
@@ -659,12 +715,36 @@
 	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
 }
 
+//###########################################################
+static void
+diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_char *cfg;
+
+	if (!cs) {
+		printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+		return;
+	}
+	cfg = (u_char *) cs->hw.diva.pci_cfg;
+	val = *cfg;
+	if (!(val &PITA_INT0_STATUS)) return; // other shared IRQ
+  interrupt_ipacx(cs);      // handler for chip
+	*cfg = PITA_INT0_STATUS;  // Reset PLX interrupt
+}
+//###########################################################
+
 void
 release_io_diva(struct IsdnCardState *cs)
 {
 	int bytecnt;
 
-	if (cs->subtyp == DIVA_IPAC_PCI) {
+//###########################################################	
+//	if (cs->subtyp == DIVA_IPAC_PCI) {
+	if ((cs->subtyp == DIVA_IPAC_PCI) || 
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+//###########################################################	
 		u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
 
 		*cfg = 0; /* disable INT0/1 */ 
@@ -711,6 +791,18 @@
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+//#######################################################################		
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+					PITA_MISC_REG);
+		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+		*ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+    MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
+//#######################################################################		
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.ctrl_reg = 0;        /* Reset On */
 		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
@@ -739,7 +831,12 @@
 {
 	int blink = 0;
 
-	if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+//########################################################	
+//	if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+	if ((cs->subtyp == DIVA_IPAC_ISA) ||
+	    (cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   )
+//########################################################	
 		return;
 	del_timer(&cs->hw.diva.tl);
 	if (cs->hw.diva.status & DIVA_ASSIGN)
@@ -782,6 +879,14 @@
 			release_io_diva(cs);
 			return(0);
 		case CARD_INIT:
+//############################################		
+			if (cs->subtyp == DIVA_IPACX_PCI) {
+				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+				*ireg = PITA_INT0_ENABLE;
+			  init_ipacx(cs, 3); // init chip and enable interrupts
+        return (0);
+			}
+//############################################		
 			if (cs->subtyp == DIVA_IPAC_PCI) {
 				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
 				*ireg = PITA_INT0_ENABLE;
@@ -818,7 +923,12 @@
 			}
 			break;
 	}
-	if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
+//############################################################	
+//	if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
+	if ((cs->subtyp != DIVA_IPAC_ISA) && 
+	    (cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   )
+//############################################################	
 		diva_led_handler(cs);
 	return(0);
 }
@@ -826,11 +936,38 @@
 static struct pci_dev *dev_diva __initdata = NULL;
 static struct pci_dev *dev_diva_u __initdata = NULL;
 static struct pci_dev *dev_diva201 __initdata = NULL;
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __initdata = {
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &diva_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_diva(struct IsdnCard *card)
 {
-	int bytecnt;
+	int bytecnt = 8;
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -863,8 +1000,75 @@
 			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
 		}
 		cs->irq = card->para[0];
-		bytecnt = 8;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.diva.cfg_reg  = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0xA1)) {
+							cs->subtyp = DIVA_IPAC_ISA;
+							cs->hw.diva.ctrl = 0;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+						} else {
+							cs->subtyp = DIVA_ISA;
+							cs->hw.diva.ctrl =
+								card->para[1] + DIVA_ISA_CTRL;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_ISA_ISAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_HSCX_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_ISA_ISAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_HSCX_ADR;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "Diva: no PCI bus present\n");
@@ -916,7 +1120,11 @@
 		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
 		return (0);
 #endif /* CONFIG_PCI */
-		if (cs->subtyp == DIVA_IPAC_PCI) {
+//########################################		
+//		if (cs->subtyp == DIVA_IPAC_PCI) {
+		if ((cs->subtyp == DIVA_IPAC_PCI) ||
+		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+//########################################		
 			cs->hw.diva.ctrl = 0;
 			cs->hw.diva.isac = 0;
 			cs->hw.diva.hscx = 0;
@@ -933,18 +1141,33 @@
 			bytecnt = 32;
 		}
 	}
-
+ready:
 	printk(KERN_INFO
 		"Diva: %s card configured at %#lx IRQ %d\n",
 		(cs->subtyp == DIVA_PCI) ? "PCI" :
 		(cs->subtyp == DIVA_ISA) ? "ISA" : 
-		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI",
+//###############################################################		
+//		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI",
+		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
+		(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
+//###############################################################		
 		cs->hw.diva.cfg_reg, cs->irq);
-	if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
-		printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
-			(cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+//###############################################################		
+//	if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
+//		printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
+//			(cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+//			cs->hw.diva.pci_cfg);
+//	if (cs->subtyp != DIVA_IPAC_PCI) {
+	if ((cs->subtyp == DIVA_IPAC_PCI)  || 
+	    (cs->subtyp == DIVA_IPACX_PCI) || 
+	    (cs->subtyp == DIVA_PCI)         )
+		printk(KERN_INFO "Diva: %s space at %#lx\n",
+			(cs->subtyp == DIVA_PCI) ? "PCI" :
+			(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
 			cs->hw.diva.pci_cfg);
-	if (cs->subtyp != DIVA_IPAC_PCI) {
+	if ((cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   ) {
+//###############################################################		
 		if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
 			printk(KERN_WARNING
 			       "HiSax: %s config port %lx-%lx already in use\n",
@@ -980,6 +1203,19 @@
 		cs->irq_func = &diva_irq_ipac_pci;
 		val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
 		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+//#####################################################	
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		cs->readisac  = &MemReadISAC_IPACX;
+		cs->writeisac = &MemWriteISAC_IPACX;
+		cs->readisacfifo  = &MemReadISACfifo_IPACX;
+		cs->writeisacfifo = &MemWriteISACfifo_IPACX;
+		cs->BC_Read_Reg  = &MemReadHSCX_IPACX;
+		cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
+		cs->BC_Send_Data = 0; // function located in ipacx module
+		cs->irq_func = &diva_irq_ipacx_pci;
+		printk(KERN_INFO "Diva: IPACX Design Id: %x\n", 
+            MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
+//#####################################################	
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.tl.function = (void *) diva_led_handler;
 		cs->hw.diva.tl.data = (long) cs;
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/elsa.c linux-2.4.20-pre3/drivers/isdn/hisax/elsa.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/elsa.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/elsa.c	Sat Aug 17 14:18:48 2002
@@ -28,6 +28,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
@@ -863,6 +864,21 @@
 static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
 static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id elsa_ids[] __initdata = {
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), 
+	  (unsigned long) "Elsa QS1000" },
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), 
+	  (unsigned long) "Elsa QS3000" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &elsa_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_elsa(struct IsdnCard *card)
 {
@@ -877,6 +893,7 @@
 	cs->hw.elsa.ctrl_reg = 0;
 	cs->hw.elsa.status = 0;
 	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
 	if (cs->typ == ISDN_CTYPE_ELSA) {
 		cs->hw.elsa.base = card->para[0];
 		printk(KERN_INFO "Elsa: Microlink IO probing\n");
@@ -938,9 +955,60 @@
 			return (0);
 		}
 	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
-		cs->hw.elsa.base = card->para[1];
-		cs->irq = card->para[0];
-		cs->subtyp = ELSA_QS1000;
+#ifdef __ISAPNP__
+		if (!card->para[1] && isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						if (pdev->function == ISAPNP_FUNCTION(0x133))
+							cs->subtyp = ELSA_QS1000;
+						else
+							cs->subtyp = ELSA_QS3000;
+						break;
+					} else {
+						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+				return(0);
+			}
+		}
+#endif
+		if (card->para[1] && card->para[0]) { 
+			cs->hw.elsa.base = card->para[1];
+			cs->irq = card->para[0];
+			if (!cs->subtyp)
+				cs->subtyp = ELSA_QS1000;
+		} else {
+			printk(KERN_ERR "Elsa PnP: no parameter\n");
+		}
 		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
 		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
 		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
@@ -1055,6 +1123,7 @@
 			break;
 		case ELSA_PCFPRO:
 		case ELSA_PCF:
+		case ELSA_QS3000:
 		case ELSA_QS3000PCI:
 			bytecnt = 16;
 			break;
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/enternow.h linux-2.4.20-pre3/drivers/isdn/hisax/enternow.h
--- linux-2.4.20-pre2/drivers/isdn/hisax/enternow.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/enternow.h	Sat Aug 17 14:18:48 2002
@@ -0,0 +1,51 @@
+/* 2001/10/02
+ *
+ * enternow.h   Header-file included by
+ *              enternow_pci.c
+ *
+ * Author       Christoph Ersfeld <info@formula-n.de>
+ *              Formula-n Europe AG (www.formula-n.com)
+ *              previously Gerdes AG
+ *
+ *
+ *              This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+/* ***************************************************************************************** *
+ * ****************************** datatypes and macros ************************************* *
+ * ***************************************************************************************** */
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+#define InByte(addr)						inb(addr)
+#define OutByte(addr,val)					outb(val,addr)
+
+
+
+/* ***************************************************************************************** *
+ * *********************************** card-specific *************************************** *
+ * ***************************************************************************************** */
+
+/* für PowerISDN PCI */
+#define TJ_AMD_IRQ 						0x20
+#define TJ_LED1 						0x40
+#define TJ_LED2 						0x80
+
+
+/* Das Fenster zum AMD...
+ * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
+ * den TigerJet i/o-Raum gemappt
+ * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+#define TJ_AMD_PORT						0xC0
+
+
+
+/* ***************************************************************************************** *
+ * *************************************** Prototypen ************************************** *
+ * ***************************************************************************************** */
+
+BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
+void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/enternow_pci.c linux-2.4.20-pre3/drivers/isdn/hisax/enternow_pci.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/enternow_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/enternow_pci.c	Sat Aug 17 14:18:48 2002
@@ -0,0 +1,447 @@
+/* enternow_pci.c,v 0.99 2001/10/02
+ *
+ * enternow_pci.c       Card-specific routines for
+ *                      Formula-n enter:now ISDN PCI ab
+ *                      Gerdes AG Power ISDN PCI
+ *                      Woerltronic SA 16 PCI
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ * Notes:
+ * This driver interfaces to netjet.c which performs B-channel
+ * processing.
+ *
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ * It isn't testet on linux 2.4 yet, so consider this code to be
+ * beta.
+ *
+ * Please don't report me any malfunction without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary the driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include "amd7930_fn.h"
+#include "enternow.h"
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "netjet.h"
+
+
+
+const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
+
+
+/* *************************** I/O-Interface functions ************************************* */
+
+
+/* cs->readisac, macro rByteAMD */
+BYTE
+ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
+{
+	/* direktes Register */
+	if(offset < 8)
+		return (InByte(cs->hw.njet.isac + 4*offset));
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		return(InByte(cs->hw.njet.isac + 4*AMD_DR));
+	}
+}
+
+/* cs->writeisac, macro wByteAMD */
+void
+WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
+{
+	/* direktes Register */
+	if(offset < 8)
+		OutByte(cs->hw.njet.isac + 4*offset, value);
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
+	}
+}
+
+
+void
+enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
+        if (!val)
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
+        else
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
+}
+
+
+static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+{
+        return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+{
+
+}
+
+
+/* ******************************************************************************** */
+
+
+static void
+reset_enpci(struct IsdnCardState *cs)
+{
+	long flags;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: reset");
+
+	save_flags(flags);
+	sti();
+	/* Reset on, (also for AMD) */
+	cs->hw.njet.ctrl_reg = 0x07;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80 ms delay */
+	schedule_timeout((80*HZ)/1000);
+	/* Reset off */
+	cs->hw.njet.ctrl_reg = 0x70;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80ms delay */
+	schedule_timeout((80*HZ)/1000);
+	restore_flags(flags);
+	cs->hw.njet.auxd = 0;  // LED-status
+	cs->hw.njet.dmactrl = 0;
+	OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
+
+}
+
+
+static int
+enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+        BYTE *chan;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
+
+        switch (mt) {
+		case CARD_RESET:
+			reset_enpci(cs);
+                        Amd7930_init(cs);
+			break;
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			break;
+		case CARD_INIT:
+			inittiger(cs);
+			Amd7930_init(cs);
+			break;
+		case CARD_TEST:
+			break;
+                case MDL_ASSIGN:
+                        /* TEI assigned, LED1 on */
+                        cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_REMOVE:
+                        /* TEI removed, LEDs off */
+	                cs->hw.njet.auxd = 0;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+                        break;
+                case MDL_BC_ASSIGN:
+                        /* activate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
+                        /* at least one b-channel in use, LED 2 on */
+                        cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_BC_RELEASE:
+                        /* deactivate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
+                        /* no b-channel active -> LED2 off */
+                        if (!(cs->dc.amd7930.lmr1 & 3)) {
+                                cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
+                                OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        }
+                        break;
+                default:
+                        break;
+
+	}
+	return(0);
+}
+
+
+static void
+enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	BYTE sval, ir;
+	long flags;
+
+
+	if (!cs) {
+		printk(KERN_WARNING "enter:now PCI: Spurious interrupt!\n");
+		return;
+	}
+
+	sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+
+        /* AMD threw an interrupt */
+	if (!(sval & TJ_AMD_IRQ)) {
+                /* read and clear interrupt-register */
+		ir = ReadByteAmd7930(cs, 0x00);
+		Amd7930_interrupt(cs, ir);
+	}
+
+	/* DMA-Interrupt: B-channel-stuff */
+	/* set bits in sval to indicate which page is free */
+
+	save_flags(flags);
+	cli();
+	/* set bits in sval to indicate which page is free */
+	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
+		/* the 2nd write page is free */
+		sval = 0x08;
+	else	/* the 1st write page is free */
+		sval = 0x04;
+	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
+		/* the 2nd read page is free */
+		sval = sval | 0x02;
+	else	/* the 1st read page is free */
+		sval = sval | 0x01;
+	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			restore_flags(flags);
+			return;
+		}
+		cs->hw.njet.irqstat0 = sval;
+		restore_flags(flags);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
+			/* we have a read dma int */
+			read_tiger(cs);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
+			/* we have a write dma int */
+			write_tiger(cs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		restore_flags(flags);
+}
+
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+/* called by config.c */
+int __init
+setup_enternow_pci(struct IsdnCard *card)
+{
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	long flags;
+
+#if CONFIG_PCI
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+        strcpy(tmp, enternow_pci_rev);
+	printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_ENTERNOW)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+	for ( ;; )
+	{
+		if (!pci_present()) {
+			printk(KERN_ERR "enter:now PCI: no PCI bus present\n");
+			return(0);
+		}
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+                        /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+			if ((dev_netjet->subsystem_vendor != 0x55) ||
+				(dev_netjet->subsystem_device != 0x02)) {
+				printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+                                printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+                                return(0);
+                        }
+		} else {
+                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
+
+		save_flags(flags);
+		sti();
+
+		/* Reset an */
+		cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		/* 50 ms Pause */
+		schedule_timeout((50*HZ)/1000);
+
+		cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		restore_flags(flags);
+
+		cs->hw.njet.auxd = 0x00; // war 0xc0
+		cs->hw.njet.dmactrl = 0;
+
+		OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+			   break;
+	}
+#else
+
+	printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (check_region(cs->hw.njet.base, bytecnt)) {
+		printk(KERN_WARNING
+			   "HiSax: %s config port %lx-%lx already in use\n",
+			   CardType[card->typ],
+			   cs->hw.njet.base,
+			   cs->hw.njet.base + bytecnt);
+		return (0);
+	} else {
+		request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN");
+	}
+	reset_enpci(cs);
+	cs->hw.njet.last_is0 = 0;
+        /* macro rByteAMD */
+        cs->readisac = &ReadByteAmd7930;
+        /* macro wByteAMD */
+        cs->writeisac = &WriteByteAmd7930;
+        cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
+
+        cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &enpci_card_msg;
+	cs->irq_func = &enpci_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+
+        return (1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/hfc_sx.c linux-2.4.20-pre3/drivers/isdn/hisax/hfc_sx.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/hfc_sx.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/hfc_sx.c	Sat Aug 17 14:18:48 2002
@@ -17,6 +17,7 @@
 #include "hfc_sx.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -1460,7 +1461,17 @@
 	return (0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), 
+	  (unsigned long) "Teles 16.3c2" },
+	{ 0, }
+};
 
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __devinit
 setup_hfcsx(struct IsdnCard *card)
@@ -1471,6 +1482,45 @@
 
 	strcpy(tmp, hfcsx_revision);
 	printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcsx.int_s1 = 0;
@@ -1553,7 +1603,3 @@
 	cs->auxcmd = &hfcsx_auxcmd;
 	return (1);
 }
-
-
-
-
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/hfcscard.c linux-2.4.20-pre3/drivers/isdn/hisax/hfcscard.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/hfcscard.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/hfcscard.c	Sat Aug 17 14:18:48 2002
@@ -12,6 +12,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -139,6 +140,36 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
+	  ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 
+	  (unsigned long) "Acer P10" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 
+	  (unsigned long) "Billion 2" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Billion 1" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 
+	  (unsigned long) "IStar PnP" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 
+	  (unsigned long) "Teles 16.3c" },
+	{ ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Tornado Tipa C" },
+	{ ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Genius Speed Surfer" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_hfcs(struct IsdnCard *card)
 {
@@ -147,6 +178,46 @@
 
 	strcpy(tmp, hfcs_revision);
 	printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
+
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcD.addr = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcD.cip = 0;
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/hisax.h linux-2.4.20-pre3/drivers/isdn/hisax/hisax.h
--- linux-2.4.20-pre2/drivers/isdn/hisax/hisax.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/hisax.h	Sat Aug 17 14:18:49 2002
@@ -68,6 +68,9 @@
 #define DL_DATA		0x0220
 #define DL_FLUSH	0x0224
 #define DL_UNIT_DATA	0x0230
+
+#define MDL_BC_RELEASE  0x0278  // Formula-n enter:now
+#define MDL_BC_ASSIGN   0x027C  // Formula-n enter:now
 #define MDL_ASSIGN	0x0280
 #define MDL_REMOVE	0x0284
 #define MDL_ERROR	0x0288
@@ -833,6 +836,17 @@
 	int ph_state;
 };
 
+struct amd7930_chip {
+	u_char lmr1;
+	u_char ph_state;
+	u_char old_state;
+	u_char flg_t3;
+	unsigned int tx_xmtlen;
+	struct timer_list timer3;
+	void (*ph_command) (struct IsdnCardState *, u_char, char *);
+	void (*setIrqMask) (struct IsdnCardState *, u_char);
+};
+
 struct icc_chip {
 	int ph_state;
 	u_char *mon_tx;
@@ -929,6 +943,7 @@
 		struct hfcpci_chip hfcpci;
 		struct hfcsx_chip hfcsx;
 		struct w6692_chip w6692;
+		struct amd7930_chip amd7930;
 		struct icc_chip icc;
 	} dc;
 	u_char *rcvbuf;
@@ -990,7 +1005,8 @@
 #define  ISDN_CTYPE_NETJET_U	38
 #define  ISDN_CTYPE_HFC_SP_PCMCIA      39
 #define  ISDN_CTYPE_DYNAMIC     40
-#define  ISDN_CTYPE_COUNT	40
+#define  ISDN_CTYPE_ENTERNOW	41
+#define  ISDN_CTYPE_COUNT	41
 
 
 #ifdef ISDN_CHIP_ISAC
@@ -1249,6 +1265,10 @@
 #define CARD_NETJET_U 0
 #endif
 
+#ifdef CONFIG_HISAX_ENTERNOW_PCI
+#define CARD_FN_ENTERNOW_PCI 1
+#endif
+
 #define TEI_PER_CARD 1
 
 /* L1 Debug */
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/ipacx.c linux-2.4.20-pre3/drivers/isdn/hisax/ipacx.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/ipacx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/ipacx.c	Sat Aug 17 14:18:49 2002
@@ -0,0 +1,1029 @@
+/* 
+ *
+ * IPACX specific routines
+ *
+ * Author       Joerg Petersohn
+ * Derived from hisax_isac.c, isac.c, hscx.c and others
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+#define __NO_VERSION__
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax_if.h"
+#include "hisax.h"
+#include "isdnl1.h"
+#include "ipacx.h"
+
+#define DBUSY_TIMER_VALUE 80
+#define TIMER3_VALUE      7000
+#define MAX_DFRAME_LEN_L1 300
+#define B_FIFO_SIZE       64
+#define D_FIFO_SIZE       32
+
+
+// ipacx interrupt mask values    
+#define _MASK_IMASK     0x2E  // global mask
+#define _MASKB_IMASK    0x0B
+#define _MASKD_IMASK    0x03  // all on
+
+//----------------------------------------------------------
+// local function declarations
+//----------------------------------------------------------
+static void ph_command(struct IsdnCardState *cs, unsigned int command);
+static inline void cic_int(struct IsdnCardState *cs);
+static void dch_l2l1(struct PStack *st, int pr, void *arg);
+static void dbusy_timer_handler(struct IsdnCardState *cs);
+static void ipacx_new_ph(struct IsdnCardState *cs);
+static void dch_bh(struct IsdnCardState *cs);
+static void dch_sched_event(struct IsdnCardState *cs, int event);
+static void dch_empty_fifo(struct IsdnCardState *cs, int count);
+static void dch_fill_fifo(struct IsdnCardState *cs);
+static inline void dch_int(struct IsdnCardState *cs);
+static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void __devinit dch_init(struct IsdnCardState *cs);
+static void bch_l2l1(struct PStack *st, int pr, void *arg);
+static void bch_sched_event(struct BCState *bcs, int event);
+static void bch_empty_fifo(struct BCState *bcs, int count);
+static void bch_fill_fifo(struct BCState *bcs);
+static void bch_int(struct IsdnCardState *cs, u_char hscx);
+static void bch_mode(struct BCState *bcs, int mode, int bc);
+static void bch_close_state(struct BCState *bcs);
+static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
+static int bch_setstack(struct PStack *st, struct BCState *bcs);
+static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
+static void __init clear_pending_ints(struct IsdnCardState *cs);
+
+//----------------------------------------------------------
+// Issue Layer 1 command to chip
+//----------------------------------------------------------
+static void 
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+	if (cs->debug &L1_DEB_ISAC)
+		debugl1(cs, "ph_command (%#x) in (%#x)", command,
+			cs->dc.isac.ph_state);
+//###################################  
+//	printk(KERN_INFO "ph_command (%#x)\n", command);
+//###################################  
+	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
+}
+
+//----------------------------------------------------------
+// Transceiver interrupt handler
+//----------------------------------------------------------
+static inline void 
+cic_int(struct IsdnCardState *cs)
+{
+	u_char event;
+
+	event = cs->readisac(cs, IPACX_CIR0) >> 4;
+	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
+//#########################################  
+//	printk(KERN_INFO "cic_int(%x)\n", event);
+//#########################################  
+  cs->dc.isac.ph_state = event;
+  dch_sched_event(cs, D_L1STATECHANGE);
+}
+
+//==========================================================
+// D channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Command entry point
+//----------------------------------------------------------
+static void
+dch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+  u_char cda1_cr, cda2_cr;
+
+	switch (pr) {
+		case (PH_DATA |REQUEST):
+			if (cs->debug &DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				dch_fill_fifo(cs);
+			}
+			break;
+      
+		case (PH_PULL |INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			dch_fill_fifo(cs);
+			break;
+      
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+
+		case (HW_RESET | REQUEST):
+		case (HW_ENABLE | REQUEST):
+			ph_command(cs, IPACX_CMD_TIM);
+			break;
+
+		case (HW_INFO3 | REQUEST):
+			ph_command(cs, IPACX_CMD_AR8);
+			break;
+
+		case (HW_TESTLOOP | REQUEST):
+      cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
+      cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
+      cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
+      cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
+			if ((long)arg &1) { // loop B1
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); 
+      }
+      else {  // B1 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); 
+      }
+			if ((long)arg &2) { // loop B2
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); 
+      }
+      else {  // B2 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); 
+      }
+			break;
+
+		case (HW_DEACTIVATE | RESPONSE):
+			skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			break;
+
+		default:
+			if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	int	rbchd, stard;
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		rbchd = cs->readisac(cs, IPACX_RBCHD);
+		stard = cs->readisac(cs, IPACX_STARD);
+		if (cs->debug) 
+      debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
+		if (!(stard &0x40)) { // D-Channel Busy
+			set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+      for (st = cs->stlist; st; st = st->next) {
+				st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
+			}
+		} else {
+			// seems we lost an interrupt; reset transceiver */
+			clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			} else {
+				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
+				debugl1(cs, "D-Channel Busy no skb");
+			}
+			cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
+		}
+	}
+}
+
+//----------------------------------------------------------
+// L1 state machine intermediate layer to isdnl1 module
+//----------------------------------------------------------
+static void
+ipacx_new_ph(struct IsdnCardState *cs)
+{
+	switch (cs->dc.isac.ph_state) {
+		case (IPACX_IND_RES):
+			ph_command(cs, IPACX_CMD_DI);
+			l1_msg(cs, HW_RESET | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_DC):
+			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+			break;
+      
+		case (IPACX_IND_DR):
+			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_PU):
+			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+			break;
+
+		case (IPACX_IND_RSY):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			break;
+
+		case (IPACX_IND_AR):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI8):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI10):
+			l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
+			break;
+      
+		default:
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// bottom half handler for D channel
+//----------------------------------------------------------
+static void
+dch_bh(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	
+	if (!cs) return;
+  
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+		if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
+		for (st = cs->stlist; st; st = st->next) {
+			st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
+		}
+	}
+  
+	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+		DChannel_proc_rcv(cs);
+  }  
+  
+	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+		DChannel_proc_xmt(cs);
+  }  
+  
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+    ipacx_new_ph(cs);
+  }  
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler dch_bh()
+//----------------------------------------------------------
+static void
+dch_sched_event(struct IsdnCardState *cs, int event)
+{
+	set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Fill buffer from receive FIFO
+//----------------------------------------------------------
+static void 
+dch_empty_fifo(struct IsdnCardState *cs, int count)
+{
+	long flags;
+	u_char *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_empty_fifo()");
+
+  // message too large, remove
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "dch_empty_fifo() incoming message too large");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+		cs->rcvidx = 0;
+		return;
+	}
+  
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+  
+	save_flags(flags);
+	cli();
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_empty_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill transmit FIFO
+//----------------------------------------------------------
+static void 
+dch_fill_fifo(struct IsdnCardState *cs)
+{
+	long flags;
+	int count;
+	u_char cmd, *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_fill_fifo()");
+    
+	if (!cs->tx_skb) return;
+	count = cs->tx_skb->len;
+	if (count <= 0) return;
+
+	if (count > D_FIFO_SIZE) {
+		count = D_FIFO_SIZE;
+		cmd   = 0x08; // XTF
+	} else {
+		cmd   = 0x0A; // XTF | XME
+	}
+  
+	save_flags(flags);
+	cli();
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, cmd);
+  
+  // set timeout for transmission contol
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "dch_fill_fifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&cs->dbusytimer);
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_fill_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// D channel interrupt handler
+//----------------------------------------------------------
+static inline void 
+dch_int(struct IsdnCardState *cs)
+{
+	struct sk_buff *skb;
+	u_char istad, rstad;
+	long flags;
+	int count;
+
+	istad = cs->readisac(cs, IPACX_ISTAD);
+//##############################################  
+//	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
+//##############################################  
+  
+	if (istad &0x80) {  // RME
+	  rstad = cs->readisac(cs, IPACX_RSTAD);
+		if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstad &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): invalid frame");
+			if ((rstad &0x40))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): RDO");
+			if (!(rstad &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): CRC error");
+	    cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC
+		} else {  // received frame ok
+			count = cs->readisac(cs, IPACX_RBCLD);
+      if (count) count--; // RSTAB is last byte
+			count &= D_FIFO_SIZE-1;
+			if (count == 0) count = D_FIFO_SIZE;
+			dch_empty_fifo(cs, count);
+			save_flags(flags);
+			cli();
+			if ((count = cs->rcvidx) > 0) {
+	      cs->rcvidx = 0;
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
+			restore_flags(flags);
+    }
+	  cs->rcvidx = 0;
+		dch_sched_event(cs, D_RCVBUFREADY);
+	}
+
+	if (istad &0x40) {  // RPF
+		dch_empty_fifo(cs, D_FIFO_SIZE);
+	}
+
+	if (istad &0x20) {  // RFO
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
+	}
+  
+  if (istad &0x10) {  // XPR
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			dch_sched_event(cs, D_CLEARBUSY);
+    if (cs->tx_skb) {
+      if (cs->tx_skb->len) {
+        dch_fill_fifo(cs);
+        goto afterXPR;
+      }
+      else {
+        dev_kfree_skb_irq(cs->tx_skb);
+        cs->tx_skb = NULL;
+        cs->tx_cnt = 0;
+      }
+    }
+    if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+      cs->tx_cnt = 0;
+      dch_fill_fifo(cs);
+    } 
+    else {
+      dch_sched_event(cs, D_XMTBUFREADY);
+    }  
+  }  
+  afterXPR:
+
+	if (istad &0x0C) {  // XDU or XMR
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
+	  if (cs->tx_skb) {
+	    skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
+	    cs->tx_cnt = 0;
+			dch_fill_fifo(cs);
+		} else {
+			printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+			debugl1(cs, "ISAC XDU no skb");
+		}
+  }
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_setstack(struct PStack *st, struct IsdnCardState *cs)
+{
+	st->l1.l1hw = dch_l2l1;
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_init(struct IsdnCardState *cs)
+{
+	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
+
+	cs->tqueue.routine  = (void *)(void *) dch_bh;
+	cs->setstack_d      = dch_setstack;
+  
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
+  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
+  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
+  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
+}
+
+
+//==========================================================
+// B channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Entry point for commands
+//----------------------------------------------------------
+static void
+bch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	long flags;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+			save_flags(flags);
+			cli();
+			if (st->l1.bcs->tx_skb) {
+				skb_queue_tail(&st->l1.bcs->squeue, skb);
+				restore_flags(flags);
+			} else {
+				st->l1.bcs->tx_skb = skb;
+				set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+				st->l1.bcs->hw.hscx.count = 0;
+				restore_flags(flags);
+        bch_fill_fifo(st->l1.bcs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (st->l1.bcs->tx_skb) {
+				printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
+				break;
+			}
+			set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			st->l1.bcs->tx_skb = skb;
+			st->l1.bcs->hw.hscx.count = 0;
+      bch_fill_fifo(st->l1.bcs);
+			break;
+		case (PH_PULL | REQUEST):
+			if (!st->l1.bcs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | REQUEST):
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | CONFIRM):
+			clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, 0, st->l1.bc);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler BChannel_bh()
+//----------------------------------------------------------
+static void
+bch_sched_event(struct BCState *bcs, int event)
+{
+	bcs->event |= 1 << event;
+	queue_task(&bcs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Read B channel fifo to receive buffer
+//----------------------------------------------------------
+static void
+bch_empty_fifo(struct BCState *bcs, int count)
+{
+	u_char *ptr, hscx;
+	struct IsdnCardState *cs;
+	long flags;
+	int cnt;
+
+	cs = bcs->cs;
+  hscx = bcs->hw.hscx.hscx;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_empty_fifo()");
+
+  // message too large, remove
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "bch_empty_fifo() incoming packet too large");
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+  
+  // Read data uninterruptible
+	save_flags(flags);
+	cli();
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	cnt = count;
+	while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+  
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill buffer to transmit FIFO
+//----------------------------------------------------------
+static void
+bch_fill_fifo(struct BCState *bcs)
+{
+	struct IsdnCardState *cs;
+	int more, count, cnt;
+	u_char *ptr, *p, hscx;
+	long flags;
+
+	cs = bcs->cs;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_fill_fifo()");
+
+	if (!bcs->tx_skb)           return;
+	if (bcs->tx_skb->len <= 0)  return;
+
+	hscx = bcs->hw.hscx.hscx;
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > B_FIFO_SIZE) {
+		more  = 1;
+		count = B_FIFO_SIZE;
+	} else {
+		count = bcs->tx_skb->len;
+	}  
+	cnt = count;
+    
+	save_flags(flags);
+	cli();
+	p = ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// B channel interrupt handler
+//----------------------------------------------------------
+static void
+bch_int(struct IsdnCardState *cs, u_char hscx)
+{
+	u_char istab;
+	struct BCState *bcs;
+	struct sk_buff *skb;
+	int count;
+	u_char rstab;
+
+	bcs = cs->bcs + hscx;
+	istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
+//##############################################  
+//	printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
+//##############################################  
+	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
+
+	if (istab &0x80) {	// RME
+		rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
+		if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstab &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
+			if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
+			if (!(rstab &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: CRC error", hscx);
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		} 
+    else {  // received frame ok
+			count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
+			if (count == 0) count = B_FIFO_SIZE;
+			bch_empty_fifo(bcs, count);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug &L1_DEB_HSCX_FIFO)
+					debugl1(cs, "bch_int Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
+		}
+		bcs->hw.hscx.rcvidx = 0;
+		bch_sched_event(bcs, B_RCVBUFREADY);
+	}
+  
+	if (istab &0x40) {	// RPF
+		bch_empty_fifo(bcs, B_FIFO_SIZE);
+
+		if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
+			// receive transparent audio data
+			if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
+				printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
+			else {
+				memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			bch_sched_event(bcs, B_RCVBUFREADY);
+		}
+	}
+  
+	if (istab &0x20) {	// RFO
+		if (cs->debug &L1_DEB_WARN) 
+      debugl1(cs, "bch_int() B-%d: RFO error", hscx);
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40);  // RRES
+	}
+
+	if (istab &0x10) {	// XPR
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+		    bch_fill_fifo(bcs);
+        goto afterXPR;
+      }
+      else {
+				if (bcs->st->lli.l1writewakeup &&
+					  (PACKET_NOACK != bcs->tx_skb->pkt_type)) {    
+					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+        }  
+			  dev_kfree_skb_irq(bcs->tx_skb);
+			  bcs->hw.hscx.count = 0; 
+			  bcs->tx_skb = NULL;
+      }
+    }    
+    if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+      bcs->hw.hscx.count = 0;
+      set_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_fill_fifo(bcs);
+    } else {
+      clear_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_sched_event(bcs, B_XMTBUFREADY);
+    }
+  }
+  afterXPR:
+
+	if (istab &0x04) {	// XDU
+    if (bcs->mode == L1_MODE_TRANS) {
+			bch_fill_fifo(bcs);
+    }  
+    else {
+      if (bcs->tx_skb) {  // restart transmitting the whole frame
+        skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+        bcs->tx_cnt += bcs->hw.hscx.count;
+        bcs->hw.hscx.count = 0;
+      }
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01);  // XRES
+      if (cs->debug &L1_DEB_WARN)
+        debugl1(cs, "bch_int() B-%d XDU error", hscx);
+    }
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_mode(struct BCState *bcs, int mode, int bc)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	int hscx = bcs->hw.hscx.hscx;
+
+        bc = bc ? 1 : 0;  // in case bc is greater than 1
+	if (cs->debug & L1_DEB_HSCX)
+		debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
+	bcs->mode = mode;
+	bcs->channel = bc;
+  
+  // map controller to according timeslot
+  if (!hscx)
+  {
+    cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHA_CR,       0x88); 
+  }
+  else
+  {
+    cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHB_CR,       0x88); 
+  }
+
+	switch (mode) {
+		case (L1_MODE_NULL):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0);  // rec off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x30);  // std adj.
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF);  // ints off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    break;
+		case (L1_MODE_TRANS):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88);  // ext transp mode
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x00);  // xxx00000
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+		case (L1_MODE_HDLC):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8);  // transp mode 0
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_close_state(struct BCState *bcs)
+{
+	bch_mode(bcs, 0, bcs->channel);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hscx.rcvbuf) {
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
+{
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate: No memory for bcs->blog\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hscx.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_setstack(struct PStack *st, struct BCState *bcs)
+{
+	bcs->channel = st->l1.bc;
+	if (bch_open_state(st->l1.hardware, bcs)) return (-1);
+	st->l1.bcs = bcs;
+	st->l2.l2l1 = bch_l2l1;
+	setstack_manager(st);
+	bcs->st = st;
+	setstack_l1_B(st);
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+bch_init(struct IsdnCardState *cs, int hscx)
+{
+	cs->bcs[hscx].BC_SetStack   = bch_setstack;
+	cs->bcs[hscx].BC_Close      = bch_close_state;
+	cs->bcs[hscx].hw.hscx.hscx  = hscx;
+	cs->bcs[hscx].cs            = cs;
+	bch_mode(cs->bcs + hscx, 0, hscx);
+}
+
+
+//==========================================================
+// Shared functions
+//==========================================================
+
+//----------------------------------------------------------
+// Main interrupt handler
+//----------------------------------------------------------
+void 
+interrupt_ipacx(struct IsdnCardState *cs)
+{
+	u_char ista;
+  
+	while ((ista = cs->readisac(cs, IPACX_ISTA))) {
+//#################################################  
+//		printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
+//#################################################  
+    if (ista &0x80) bch_int(cs, 0); // B channel interrupts
+    if (ista &0x40) bch_int(cs, 1);
+    
+    if (ista &0x01) dch_int(cs);    // D channel
+    if (ista &0x10) cic_int(cs);    // Layer 1 state
+  }  
+}
+
+//----------------------------------------------------------
+// Clears chip interrupt status
+//----------------------------------------------------------
+static void __init
+clear_pending_ints(struct IsdnCardState *cs)
+{
+	int ista;
+
+  // all interrupts off
+  cs->writeisac(cs, IPACX_MASK, 0xff);
+	cs->writeisac(cs, IPACX_MASKD, 0xff);
+	cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
+	cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
+  
+  ista = cs->readisac(cs, IPACX_ISTA); 
+  if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
+  if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
+  if (ista &0x10) cs->readisac(cs, IPACX_CIR0);
+  if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); 
+}
+
+//----------------------------------------------------------
+// Does chip configuration work
+// Work to do depends on bit mask in part
+//----------------------------------------------------------
+void __init
+init_ipacx(struct IsdnCardState *cs, int part)
+{
+	if (part &1) {  // initialise chip
+//##################################################  
+//	printk(KERN_INFO "init_ipacx(%x)\n", part);
+//##################################################  
+		clear_pending_ints(cs);
+		bch_init(cs, 0);
+		bch_init(cs, 1);
+		dch_init(cs);
+	}
+	if (part &2) {  // reenable all interrupts and start chip
+		cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
+		cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
+		cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
+		cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
+
+    // reset HDLC Transmitters/receivers
+		cs->writeisac(cs, IPACX_CMDRD, 0x41); 
+    cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
+    cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
+  	ph_command(cs, IPACX_CMD_RES);
+	}
+}
+
+//----------------- end of file -----------------------
+
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/ipacx.h linux-2.4.20-pre3/drivers/isdn/hisax/ipacx.h
--- linux-2.4.20-pre2/drivers/isdn/hisax/ipacx.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/isdn/hisax/ipacx.h	Sat Aug 17 14:18:49 2002
@@ -0,0 +1,161 @@
+/*
+ *
+ * IPACX specific defines
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/* All Registers original Siemens Spec  */
+
+#ifndef INCLUDE_IPACX_H
+#define INCLUDE_IPACX_H
+
+/* D-channel registers   */
+#define IPACX_RFIFOD        0x00    /* RD       */
+#define IPACX_XFIFOD        0x00    /* WR       */
+#define IPACX_ISTAD         0x20    /* RD       */
+#define IPACX_MASKD         0x20    /* WR       */
+#define IPACX_STARD         0x21    /* RD       */
+#define IPACX_CMDRD         0x21    /* WR       */
+#define IPACX_MODED         0x22    /* RD/WR    */
+#define IPACX_EXMD1         0x23    /* RD/WR    */
+#define IPACX_TIMR1         0x24    /* RD/WR    */
+#define IPACX_SAP1          0x25    /* WR       */
+#define IPACX_SAP2          0x26    /* WR       */
+#define IPACX_RBCLD         0x26    /* RD       */
+#define IPACX_RBCHD         0x27    /* RD       */
+#define IPACX_TEI1          0x27    /* WR       */
+#define IPACX_TEI2          0x28    /* WR       */
+#define IPACX_RSTAD         0x28    /* RD       */
+#define IPACX_TMD           0x29    /* RD/WR    */
+#define IPACX_CIR0          0x2E    /* RD       */
+#define IPACX_CIX0          0x2E    /* WR       */
+#define IPACX_CIR1          0x2F    /* RD       */
+#define IPACX_CIX1          0x2F    /* WR       */
+
+/* Transceiver registers    */
+#define IPACX_TR_CONF0      0x30    /* RD/WR    */
+#define IPACX_TR_CONF1      0x31    /* RD/WR    */
+#define IPACX_TR_CONF2      0x32    /* RD/WR    */
+#define IPACX_TR_STA        0x33    /* RD       */
+#define IPACX_TR_CMD        0x34    /* RD/WR    */
+#define IPACX_SQRR1         0x35    /* RD       */
+#define IPACX_SQXR1         0x35    /* WR       */
+#define IPACX_SQRR2         0x36    /* RD       */
+#define IPACX_SQXR2         0x36    /* WR       */
+#define IPACX_SQRR3         0x37    /* RD       */
+#define IPACX_SQXR3         0x37    /* WR       */
+#define IPACX_ISTATR        0x38    /* RD       */
+#define IPACX_MASKTR        0x39    /* RD/WR    */
+#define IPACX_TR_MODE       0x3A    /* RD/WR    */
+#define IPACX_ACFG1         0x3C    /* RD/WR    */
+#define IPACX_ACFG2         0x3D    /* RD/WR    */
+#define IPACX_AOE           0x3E    /* RD/WR    */
+#define IPACX_ARX           0x3F    /* RD       */
+#define IPACX_ATX           0x3F    /* WR       */
+
+/* IOM: Timeslot, DPS, CDA  */
+#define IPACX_CDA10         0x40    /* RD/WR    */
+#define IPACX_CDA11         0x41    /* RD/WR    */
+#define IPACX_CDA20         0x42    /* RD/WR    */
+#define IPACX_CDA21         0x43    /* RD/WR    */
+#define IPACX_CDA_TSDP10    0x44    /* RD/WR    */
+#define IPACX_CDA_TSDP11    0x45    /* RD/WR    */
+#define IPACX_CDA_TSDP20    0x46    /* RD/WR    */
+#define IPACX_CDA_TSDP21    0x47    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC1 0x48    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC2 0x49    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC1 0x4A    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC2 0x4B    /* RD/WR    */
+#define IPACX_TR_TSDP_BC1   0x4C    /* RD/WR    */
+#define IPACX_TR_TSDP_BC2   0x4D    /* RD/WR    */
+#define IPACX_CDA1_CR       0x4E    /* RD/WR    */
+#define IPACX_CDA2_CR       0x4F    /* RD/WR    */
+
+/* IOM: Contol, Sync transfer, Monitor    */
+#define IPACX_TR_CR         0x50    /* RD/WR    */
+#define IPACX_TRC_CR        0x50    /* RD/WR    */
+#define IPACX_BCHA_CR       0x51    /* RD/WR    */
+#define IPACX_BCHB_CR       0x52    /* RD/WR    */
+#define IPACX_DCI_CR        0x53    /* RD/WR    */
+#define IPACX_DCIC_CR       0x53    /* RD/WR    */
+#define IPACX_MON_CR        0x54    /* RD/WR    */
+#define IPACX_SDS1_CR       0x55    /* RD/WR    */
+#define IPACX_SDS2_CR       0x56    /* RD/WR    */
+#define IPACX_IOM_CR        0x57    /* RD/WR    */
+#define IPACX_STI           0x58    /* RD       */
+#define IPACX_ASTI          0x58    /* WR       */
+#define IPACX_MSTI          0x59    /* RD/WR    */
+#define IPACX_SDS_CONF      0x5A    /* RD/WR    */
+#define IPACX_MCDA          0x5B    /* RD       */
+#define IPACX_MOR           0x5C    /* RD       */
+#define IPACX_MOX           0x5C    /* WR       */
+#define IPACX_MOSR          0x5D    /* RD       */
+#define IPACX_MOCR          0x5E    /* RD/WR    */
+#define IPACX_MSTA          0x5F    /* RD       */
+#define IPACX_MCONF         0x5F    /* WR       */
+
+/* Interrupt and general registers */
+#define IPACX_ISTA          0x60    /* RD       */
+#define IPACX_MASK          0x60    /* WR       */
+#define IPACX_AUXI          0x61    /* RD       */
+#define IPACX_AUXM          0x61    /* WR       */
+#define IPACX_MODE1         0x62    /* RD/WR    */
+#define IPACX_MODE2         0x63    /* RD/WR    */
+#define IPACX_ID            0x64    /* RD       */
+#define IPACX_SRES          0x64    /* WR       */
+#define IPACX_TIMR2         0x65    /* RD/WR    */
+
+/* B-channel registers */
+#define IPACX_OFF_B1        0x70
+#define IPACX_OFF_B2        0x80
+
+#define IPACX_ISTAB         0x00    /* RD       */
+#define IPACX_MASKB         0x00    /* WR       */
+#define IPACX_STARB         0x01    /* RD       */
+#define IPACX_CMDRB         0x01    /* WR       */
+#define IPACX_MODEB         0x02    /* RD/WR    */
+#define IPACX_EXMB          0x03    /* RD/WR    */
+#define IPACX_RAH1          0x05    /* WR       */
+#define IPACX_RAH2          0x06    /* WR       */
+#define IPACX_RBCLB         0x06    /* RD       */
+#define IPACX_RBCHB         0x07    /* RD       */
+#define IPACX_RAL1          0x07    /* WR       */
+#define IPACX_RAL2          0x08    /* WR       */
+#define IPACX_RSTAB         0x08    /* RD       */
+#define IPACX_TMB           0x09    /* RD/WR    */
+#define IPACX_RFIFOB        0x0A    /*- RD      */
+#define IPACX_XFIFOB        0x0A    /*- WR      */
+
+/* Layer 1 Commands */
+#define IPACX_CMD_TIM    0x0
+#define IPACX_CMD_RES    0x1
+#define IPACX_CMD_SSP    0x2
+#define IPACX_CMD_SCP    0x3
+#define IPACX_CMD_AR8    0x8
+#define IPACX_CMD_AR10   0x9
+#define IPACX_CMD_ARL    0xa
+#define IPACX_CMD_DI     0xf
+
+/* Layer 1 Indications */
+#define IPACX_IND_DR     0x0
+#define IPACX_IND_RES    0x1
+#define IPACX_IND_TMA    0x2
+#define IPACX_IND_SLD    0x3
+#define IPACX_IND_RSY    0x4
+#define IPACX_IND_DR6    0x5
+#define IPACX_IND_PU     0x7
+#define IPACX_IND_AR     0x8
+#define IPACX_IND_ARL    0xa
+#define IPACX_IND_CVR    0xb
+#define IPACX_IND_AI8    0xc
+#define IPACX_IND_AI10   0xd
+#define IPACX_IND_AIL    0xe
+#define IPACX_IND_DC     0xf
+
+extern void init_ipacx(struct IsdnCardState *cs, int part);
+extern void interrupt_ipacx(struct IsdnCardState *cs);
+
+#endif
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/isurf.c linux-2.4.20-pre3/drivers/isdn/hisax/isurf.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/isurf.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/isurf.c	Sat Aug 17 14:18:49 2002
@@ -16,6 +16,7 @@
 #include "isac.h"
 #include "isar.h"
 #include "isdnl1.h"
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -193,6 +194,10 @@
 	return(isar_auxcmd(cs, ic));
 }
 
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_surf __devinitdata = NULL;
+#endif
+
 int __init
 setup_isurf(struct IsdnCard *card)
 {
@@ -210,9 +215,48 @@
 		cs->hw.isurf.phymem = card->para[2];
 		cs->irq = card->para[0];
 	} else {
+#ifdef __ISAPNP__
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if (isapnp_present()) {
+			cs->subtyp = 0;
+			if ((pb = isapnp_find_card(
+				ISAPNP_VENDOR('S', 'I', 'E'),
+				ISAPNP_FUNCTION(0x0010), pnp_surf))) {
+				pnp_surf = pb;
+				pd = NULL;
+				if (!(pd = isapnp_find_dev(pnp_surf,
+					ISAPNP_VENDOR('S', 'I', 'E'),
+					ISAPNP_FUNCTION(0x0010), pd))) {
+					printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
+					return (0);
+				}
+				pd->prepare(pd);
+				pd->deactivate(pd);
+				pd->activate(pd);
+				cs->hw.isurf.reset = pd->resource[0].start;
+				cs->hw.isurf.phymem = pd->resource[1].start;
+				cs->irq = pd->irq_resource[0].start;
+				if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
+					printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
+						cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
+					pd->deactivate(pd);
+					return(0);
+				}
+			} else {
+				printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
+			return(0);
+		}
+#else
 		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
 			CardType[card->typ]);
 		return (0);
+#endif
 	}
 	if (check_region(cs->hw.isurf.reset, 1)) {
 		printk(KERN_WARNING
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/ix1_micro.c linux-2.4.20-pre3/drivers/isdn/hisax/ix1_micro.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/ix1_micro.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/ix1_micro.c	Sat Aug 17 14:18:49 2002
@@ -19,6 +19,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -218,6 +219,21 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id itk_ids[] __initdata = {
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 
+	  (unsigned long) "ITK micro 2" },
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 
+	  (unsigned long) "ITK micro 2." },
+	{ 0, }
+};
+
+static struct isapnp_device_id *idev = &itk_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_ix1micro(struct IsdnCard *card)
@@ -230,6 +246,45 @@
 	if (cs->typ != ISDN_CTYPE_IX1MICROR2)
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(idev->card_vendor) {
+			if ((pb = isapnp_find_card(idev->card_vendor,
+				idev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					idev->vendor, idev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)idev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
+				}
+			}
+			idev++;
+			pnp_c=NULL;
+		} 
+		if (!idev->card_vendor) {
+			printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	/* IO-Ports */
 	cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
 	cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/netjet.c linux-2.4.20-pre3/drivers/isdn/hisax/netjet.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/netjet.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/netjet.c	Sat Aug 17 14:18:49 2002
@@ -8,7 +8,9 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
- * Thanks to Traverse Technologie Australia for documents and information
+ * Thanks to Traverse Technologies Australia for documents and information
+ *
+ * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
  *
  */
 
@@ -133,6 +135,7 @@
 mode_tiger(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
+        u_char led;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "Tiger mode %d bchan %d/%d",
@@ -154,6 +157,15 @@
 					cs->hw.njet.dmactrl);
 				byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
 			}
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led off
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                led = ~led;
+                                cs->hw.njet.auxd &= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 		case (L1_MODE_TRANS):
 			break;
@@ -179,6 +191,14 @@
 			bcs->hw.tiger.sendp = bcs->hw.tiger.send;
 			bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
 			test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led on
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                cs->hw.njet.auxd |= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 	}
 	if (cs->debug & L1_DEB_HSCX)
@@ -854,9 +874,13 @@
 		case (PH_ACTIVATE | REQUEST):
 			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/niccy.c linux-2.4.20-pre3/drivers/isdn/hisax/niccy.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/niccy.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/niccy.c	Sat Aug 17 14:18:49 2002
@@ -22,6 +22,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 const char *niccy_revision = "$Revision: 1.1.4.1 $";
@@ -238,6 +239,9 @@
 }
 
 static struct pci_dev *niccy_dev __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __init
 setup_niccy(struct IsdnCard *card)
@@ -249,7 +253,39 @@
 	printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_NICCY)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if ((pb = isapnp_find_card(
+			ISAPNP_VENDOR('S', 'D', 'A'),
+			ISAPNP_FUNCTION(0x0150), pnp_c))) {
+			pnp_c = pb;
+			pd = NULL;
+			if (!(pd = isapnp_find_dev(pnp_c,
+				ISAPNP_VENDOR('S', 'D', 'A'),
+				ISAPNP_FUNCTION(0x0150), pd))) {
+				printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
+				return (0);
+			}
+			pd->prepare(pd);
+			pd->deactivate(pd);
+			pd->activate(pd);
+			card->para[1] = pd->resource[0].start;
+			card->para[2] = pd->resource[1].start;
+			card->para[0] = pd->irq_resource[0].start;
+			if (!card->para[0] || !card->para[1] || !card->para[2]) {
+				printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
+					card->para[0], card->para[1], card->para[2]);
+				pd->deactivate(pd);
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
+		}
+	}
+#endif
 	if (card->para[1]) {
 		cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
 		cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/nj_s.c linux-2.4.20-pre3/drivers/isdn/hisax/nj_s.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/nj_s.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/nj_s.c	Sat Aug 17 14:18:49 2002
@@ -184,6 +184,14 @@
 				printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
 				return(0);
 			}
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+			if ((dev_netjet->subsystem_vendor == 0x55) &&
+				(dev_netjet->subsystem_device == 0x02)) {
+				printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+				printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+				return(0);
+			}
+			/* end new code */
 		} else {
 			printk(KERN_WARNING "NETjet-S: No PCI card found\n");
 			return(0);
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/sedlbauer.c linux-2.4.20-pre3/drivers/isdn/hisax/sedlbauer.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/sedlbauer.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/sedlbauer.c	Sat Aug 17 14:18:49 2002
@@ -48,6 +48,7 @@
 #include "isar.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -530,6 +531,21 @@
 
 static struct pci_dev *dev_sedl __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id sedl_ids[] __initdata = {
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), 
+	  (unsigned long) "Speed win" },
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), 
+	  (unsigned long) "Speed Fax+" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &sedl_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
@@ -565,6 +581,57 @@
 			bytecnt = 16;
 		}
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.sedl.cfg_reg = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0x2)) {
+							cs->subtyp = SEDL_SPEED_FAX;
+							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+							bytecnt = 16;
+						} else {
+							cs->subtyp = SEDL_SPEED_CARD_WIN;
+							cs->hw.sedl.chip = SEDL_CHIP_TEST;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 /* Probe for Sedlbauer speed pci */
 #if CONFIG_PCI
 		if (!pci_present()) {
@@ -630,7 +697,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}	
-	
+ready:	
 	/* In case of the sedlbauer pcmcia card, this region is in use,
 	 * reserved for us by the card manager. So we do not check it
 	 * here, it would fail.
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/st5481_usb.c linux-2.4.20-pre3/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/st5481_usb.c	Sat Aug 17 14:18:17 2002
+++ linux-2.4.20-pre3/drivers/isdn/hisax/st5481_usb.c	Sat Aug 17 14:18:49 2002
@@ -41,9 +41,9 @@
 		(unsigned char *)&ctrl->msg_fifo.data[r_index];
 	
 	DBG(1,"request=0x%02x,value=0x%04x,index=%x",
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.request,
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.value,
-	    ((struct ctrl_msg *)urb->setup_packet)->dr.index);
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
+	    ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
 
 	// Prepare the URB
 	urb->dev = adapter->usb_dev;
@@ -69,11 +69,11 @@
 	}
 	ctrl_msg = &ctrl->msg_fifo.data[w_index]; 
    
-	ctrl_msg->dr.requesttype = requesttype;
-	ctrl_msg->dr.request = request;
-	ctrl_msg->dr.value = cpu_to_le16p(&value);
-	ctrl_msg->dr.index = cpu_to_le16p(&index);
-	ctrl_msg->dr.length = 0;
+	ctrl_msg->dr.bRequestType = requesttype;
+	ctrl_msg->dr.bRequest = request;
+	ctrl_msg->dr.wValue = cpu_to_le16p(&value);
+	ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
+	ctrl_msg->dr.wLength = 0;
 	ctrl_msg->complete = complete;
 	ctrl_msg->context = context;
 
@@ -140,17 +140,17 @@
 
 	ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
 	
-	if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) {
+	if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
 	        /* Special case handling for pipe reset */
-		le16_to_cpus(&ctrl_msg->dr.index);
+		le16_to_cpus(&ctrl_msg->dr.wIndex);
 		usb_endpoint_running(adapter->usb_dev,
-				     ctrl_msg->dr.index & ~USB_DIR_IN, 
-				     (ctrl_msg->dr.index & USB_DIR_IN) == 0);
+				     ctrl_msg->dr.wIndex & ~USB_DIR_IN, 
+				     (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0);
 
 		/* toggle is reset on clear */
 		usb_settoggle(adapter->usb_dev, 
-			      ctrl_msg->dr.index & ~USB_DIR_IN, 
-			      (ctrl_msg->dr.index & USB_DIR_IN) == 0,
+			      ctrl_msg->dr.wIndex & ~USB_DIR_IN, 
+			      (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0,
 			      0);
 
 
diff -urN linux-2.4.20-pre2/drivers/isdn/hisax/teles3.c linux-2.4.20-pre3/drivers/isdn/hisax/teles3.c
--- linux-2.4.20-pre2/drivers/isdn/hisax/teles3.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/hisax/teles3.c	Sat Aug 17 14:18:49 2002
@@ -15,6 +15,7 @@
  */
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -254,6 +255,24 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id teles_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
+	  (unsigned long) "Teles 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
+	  ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), 
+	  (unsigned long) "Creatix 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
+	  ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), 
+	  (unsigned long) "Compaq ISDN S0" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *tdev = &teles_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_teles3(struct IsdnCard *card)
 {
@@ -267,6 +286,47 @@
 	    && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(tdev->card_vendor) {
+			if ((pb = isapnp_find_card(tdev->card_vendor,
+				tdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					tdev->vendor, tdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)tdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[3] = pd->resource[2].start;
+					card->para[2] = pd->resource[1].start;
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1] || !card->para[2]) {
+						printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
+						card->para[0], card->para[1], card->para[2]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
+				}
+			}
+			tdev++;
+			pnp_c=NULL;
+		} 
+		if (!tdev->card_vendor) {
+			printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	if (cs->typ == ISDN_CTYPE_16_3) {
 		cs->hw.teles3.cfg_reg = card->para[1];
 		switch (cs->hw.teles3.cfg_reg) {
diff -urN linux-2.4.20-pre2/drivers/isdn/isdn_net.c linux-2.4.20-pre3/drivers/isdn/isdn_net.c
--- linux-2.4.20-pre2/drivers/isdn/isdn_net.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/isdn_net.c	Sat Aug 17 14:18:49 2002
@@ -9,6 +9,14 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
+ * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 
+ *                                       guy@traverse.com.au
+ * Outgoing calls - looks for a 'V' in first char of dialed number
+ * Incoming calls - checks first character of eaz as follows:
+ *   Numeric - accept DATA only - original functionality
+ *   'V'     - accept VOICE (DOV) only
+ *   'B'     - accept BOTH DATA and DOV types
+ *
  * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
  *           for info on the protocol, see 
  *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
@@ -570,6 +578,7 @@
 	int i;
 	unsigned long flags;
 	isdn_ctrl cmd;
+        u_char *phone_number;
 
 	while (p) {
 		isdn_net_local *lp = p->local;
@@ -668,7 +677,20 @@
 							break;
 						}
 
-					sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
+					cmd.driver = lp->isdn_device;
+					cmd.command = ISDN_CMD_DIAL;
+					cmd.parm.setup.si2 = 0;
+
+                                        /* check for DOV */
+                                        phone_number = lp->dial->num;
+                                        if ((*phone_number == 'v') ||
+					    (*phone_number == 'V')) { /* DOV call */
+                                                cmd.parm.setup.si1 = 1;
+                                        } else { /* DATA call */
+                                                cmd.parm.setup.si1 = 7;
+					}
+
+					strcpy(cmd.parm.setup.phone, phone_number);
 					/*
 					 * Switch to next number or back to start if at end of list.
 					 */
@@ -688,10 +710,6 @@
 						}
 					}
 					restore_flags(flags);
-					cmd.driver = lp->isdn_device;
-					cmd.command = ISDN_CMD_DIAL;
-					cmd.parm.setup.si1 = 7;
-					cmd.parm.setup.si2 = 0;
 					sprintf(cmd.parm.setup.eazmsn, "%s",
 						isdn_map_eaz2msn(lp->msn, cmd.driver));
 					i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
@@ -700,8 +718,9 @@
 						dev->usage[i] |= ISDN_USAGE_OUTGOING;
 						isdn_info_update();
 					}
-					printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
-					       lp->dialretry, cmd.parm.setup.phone);
+					printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+					       lp->dialretry, cmd.parm.setup.phone,
+					       (cmd.parm.setup.si1 == 1) ? "DOV" : "");
 					lp->dtimer = 0;
 #ifdef ISDN_DEBUG_NET_DIAL
 					printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
@@ -1747,10 +1766,6 @@
 	}
 
 	switch (type) {
-	case CISCO_TYPE_INET:
-		skb->protocol = htons(ETH_P_IP);
-		netif_rx(skb);
-		break;
 	case CISCO_TYPE_SLARP:
 		isdn_net_ciscohdlck_slarp_in(lp, skb);
 		goto out_free;
@@ -1760,11 +1775,11 @@
 				"\"no cdp enable\" on cisco.\n", lp->name);
 		goto out_free;
 	default:
-		printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
-		       lp->name, type);
-		goto out_free;
+		/* no special cisco protocol */
+		skb->protocol = htons(type);
+		netif_rx(skb);
+		return;
 	}
-	return;
 
  out_free:
 	kfree_skb(skb);
@@ -2145,6 +2160,8 @@
 	isdn_net_phone *n;
 	ulong flags;
 	char nr[32];
+	char *my_eaz;
+
 	/* Search name in netdev-chain */
 	save_flags(flags);
 	cli();
@@ -2163,15 +2180,17 @@
 		eaz = setup->eazmsn;
 	if (dev->net_verbose > 1)
 		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
-	/* Accept only calls with Si1 = 7 (Data-Transmission) */
-	if (si1 != 7) {
-		restore_flags(flags);
-		if (dev->net_verbose > 1)
-			printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
-		return 0;
-	}
-	n = (isdn_net_phone *) 0;
-	p = dev->netdev;
+        /* Accept DATA and VOICE calls at this stage
+        local eaz is checked later for allowed call types */
+        if ((si1 != 7) && (si1 != 1)) {
+                restore_flags(flags);
+                if (dev->net_verbose > 1)
+                        printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
+                return 0;
+        }
+
+n = (isdn_net_phone *) 0;
+p = dev->netdev;
 	ematch = wret = swapped = 0;
 #ifdef ISDN_DEBUG_NET_ICALL
 	printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
@@ -2191,8 +2210,25 @@
 				break;
 		}
 		swapped = 0;
-		if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di))))
-			ematch = 1;
+                /* check acceptable call types for DOV */
+                my_eaz = isdn_map_eaz2msn(lp->msn, di);
+                if (si1 == 1) { /* it's a DOV call, check if we allow it */
+                        if (*my_eaz == 'v' || *my_eaz == 'V' ||
+			    *my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                        else
+                                my_eaz = 0; /* force non match */
+                } else { /* it's a DATA call, check if we allow it */
+                        if (*my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                }
+                if (my_eaz)
+                        matchret = isdn_msncmp(eaz, my_eaz);
+                else
+                        matchret = 1;
+                if (!matchret)
+                        ematch = 1;
+
 		/* Remember if more numbers eventually can match */
 		if (matchret > wret)
 			wret = matchret;
diff -urN linux-2.4.20-pre2/drivers/isdn/isdn_net.h linux-2.4.20-pre3/drivers/isdn/isdn_net.h
--- linux-2.4.20-pre2/drivers/isdn/isdn_net.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre3/drivers/isdn/isdn_net.h	Sat Aug 17 14:18:49 2002
@@ -26,7 +26,6 @@
 #define CISCO_ADDR_BROADCAST  0x8f
 #define CISCO_CTRL            0x00
 #define CISCO_TYPE_CDP        0x2000
-#define CISCO_TYPE_INET       0x0800
 #define CISCO_TYPE_SLARP      0x8035
 #define CISCO_SLARP_REQUEST   0
 #define CISCO_SLARP_REPLY     1
@@ -107,6 +106,8 @@
 	spin_lock_irqsave(&nd->queue_lock, flags);
 
 	lp = nd->queue;
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) nlp:%s(%p) last(%p)\n",
+//		lp->name, lp, nlp->name, nlp, lp->last); 
 	nlp->last = lp->last;
 	lp->last->next = nlp;
 	lp->last = nlp;
@@ -126,12 +127,20 @@
 	if (lp->master)
 		master_lp = (isdn_net_local *) lp->master->priv;
 
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
+//		lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); 
 	spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
 	lp->last->next = lp->next;
 	lp->next->last = lp->last;
-	if (master_lp->netdev->queue == lp)
+	if (master_lp->netdev->queue == lp) {
 		master_lp->netdev->queue = lp->next;
+		if (lp->next == lp) { /* last in queue */
+			master_lp->netdev->queue = master_lp->netdev->local;
+		}
+	}
 	lp->next = lp->last = lp;	/* (re)set own pointers */
+//	printk(KERN_DEBUG __FUNCTION__": mndq(%p)\n",
+//		master_lp->netdev->queue); 
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
 }
 
diff -urN linux-2.4.20-pre2/drivers/isdn/isdn_ppp.c linux-2.4.20-pre3/drivers/isdn/isdn_ppp.c
--- linux-2.4.20-pre2/drivers/isdn/isdn_ppp.c	Sat Aug 17 14:18:17 2002
+++ linux-2.4.20-pre3/drivers/isdn/isdn_ppp.c	Sat Aug 17 14:18:49 2002
@@ -107,8 +107,11 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return 0;
+	}
 
 	save_flags(flags);
 	cli();
@@ -124,7 +127,12 @@
 	lp->netdev->pb->ref_ct--;
 	spin_unlock(&lp->netdev->pb->lock);
 #endif /* CONFIG_ISDN_MPP */
-
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) now invalid\n",
+			lp->ppp_slot);
+		restore_flags(flags);
+		return 0;
+	}
 	is = ippp_table[lp->ppp_slot];
 	if ((is->state & IPPP_CONNECT))
 		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
@@ -220,12 +228,13 @@
 void
 isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 {
-	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return;
-
+	}
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-
-		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -238,13 +247,14 @@
 {
 	struct ippp_struct *is;
 
-	if (slot < 0 || slot >= ISDN_MAX_CHANNELS)
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+			slot);
 		return 0;
+	}
 	is = ippp_table[slot];
-
 	if (is->state)
 		wake_up_interruptible(&is->wq);
-
 	is->state = IPPP_CLOSEWAIT;
 	return 1;
 }
@@ -282,8 +292,9 @@
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
-
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+	
+	printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
+	       slot, min, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -332,12 +343,20 @@
 		return;
 	is = file->private_data;
 
+	if (!is) {
+		printk(KERN_ERR __FUNCTION__": no file->private_data\n");
+		return;
+	}
 	if (is->debug & 0x1)
 		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
 
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
 
+		if (!p) {
+			printk(KERN_ERR __FUNCTION__": no lp->netdev\n");
+			return;
+		}
 		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
 		/*
 		 * isdn_net_hangup() calls isdn_ppp_free()
@@ -629,7 +648,7 @@
 	struct ippp_struct *is;
 
 	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
-		printk(KERN_WARNING "ippp: illegal slot.\n");
+		printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
 		return 0;
 	}
 	is = ippp_table[slot];
@@ -906,7 +925,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return;
 	}
@@ -959,7 +979,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		goto drop_packet;
 	}
 	is = ippp_table[slot];
@@ -967,7 +988,8 @@
  	if (lp->master) { // FIXME?
  		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
  		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
+ 				lp->ppp_slot);
 			goto drop_packet;
  		}
  	}
@@ -1001,6 +1023,11 @@
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+			if (net_dev->local->ppp_slot < 0) {
+				printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+					net_dev->local->ppp_slot);
+				goto drop_packet;
+			}
 			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
 				goto drop_packet;
@@ -1022,6 +1049,11 @@
 				}
 				skb_put(skb, skb_old->len + 128);
 				memcpy(skb->data, skb_old->data, skb_old->len);
+				if (net_dev->local->ppp_slot < 0) {
+					printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+						net_dev->local->ppp_slot);
+					goto drop_packet;
+				}
 				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
 				kfree_skb(skb_old);
@@ -1110,7 +1142,8 @@
 
 	slot = mlp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			mlp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1145,7 +1178,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1350,8 +1384,15 @@
 
 static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
 {
-	struct ippp_struct * is = ippp_table[lp->ppp_slot];
-   
+	struct ippp_struct * is;
+
+	if (lp->ppp_slot < 0) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return(-EINVAL);
+	}
+
+	is = ippp_table[lp->ppp_slot];
 	if (add_to) {
 		if( lp->netdev->pb )
 			lp->netdev->pb->ref_ct--;
@@ -1397,7 +1438,8 @@
         stats = &mp->stats;
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		stats->frame_drops++;
 		dev_kfree_skb(skb);
 		spin_unlock_irqrestore(&mp->lock, flags);
@@ -1433,7 +1475,8 @@
 	for (lpq = net_dev->queue;;) {
 		slot = lpq->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-			printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+			printk(KERN_ERR __FUNCTION__": lpq->ppp_slot(%d)\n",
+				lpq->ppp_slot);
 		} else {
 			u32 lls = ippp_table[slot]->last_link_seqno;
 			if (MP_LT(lls, minseq))
@@ -1665,9 +1708,14 @@
 	struct sk_buff * skb;
 	unsigned int tot_len;
 
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
 	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
 		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
-			printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
+			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
 					"len %d\n", MP_SEQ(from), from->len );
 		skb = from;
 		skb_pull(skb, MP_HEADER_LEN);
@@ -2429,18 +2477,31 @@
 static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
 	 struct sk_buff *skb,int proto)
 {
-	struct ippp_struct *is = ippp_table[lp->ppp_slot];
+	struct ippp_struct *is;
 	struct ippp_struct *mis;
 	int len;
 	struct isdn_ppp_resetparams rsparm;
 	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
 
-	printk(KERN_DEBUG "Received CCP frame from peer\n");
+	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
+		lp->ppp_slot);
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
+	is = ippp_table[lp->ppp_slot];
 	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-	if(lp->master)
-		mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-	else
+	if(lp->master) {
+		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
 		mis = is;
 
 	switch(skb->data[0]) {
@@ -2592,13 +2653,18 @@
 
 static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
-	struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
-	int proto;
+	struct ippp_struct *mis,*is;
+	int proto, slot = lp->ppp_slot;
 	unsigned char *data;
 
 	if(!skb || skb->len < 3)
 		return;
-
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			slot);
+		return;
+	}	
+	is = ippp_table[slot];
 	/* Daemon may send with or without address and control field comp */
 	data = skb->data;
 	if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
@@ -2614,12 +2680,17 @@
 	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
 	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-        if(lp->master)
-                mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-        else
-                mis = is;
-	
-	if(mis != is)
+	if (lp->master) {
+		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
+		mis = is;
+	if (mis != is)
 		printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
 	
         switch(data[2]) {
diff -urN linux-2.4.20-pre2/drivers/md/lvm-snap.c linux-2.4.20-pre3/drivers/md/lvm-snap.c
--- linux-2.4.20-pre2/drivers/md/lvm-snap.c	Sat Aug 17 14:18:17 2002
+++ linux-2.4.20-pre3/drivers/md/lvm-snap.c	Sat Aug 17 14:18:49 2002
@@ -130,7 +130,8 @@
 				list_move(next, hash_table);
 #else
 				list_del(next);
-#endif				list_add(next, hash_table);
+				list_add(next, hash_table);
+#endif
 			}
 			ret = exception;
 			break;
diff -urN linux-2.4.20-pre2/drivers/md/md.c linux-2.4.20-pre3/drivers/md/md.c
--- linux-2.4.20-pre2/drivers/md/md.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/md/md.c	Sat Aug 17 14:18:49 2002
@@ -724,9 +724,9 @@
 	 * Make sure nobody else is using this mddev
 	 * (careful, we rely on the global kernel lock here)
 	 */
-	while (md_atomic_read(&mddev->resync_sem.count) != 1)
+	while (sem_getcount(&mddev->resync_sem) != 1)
 		schedule();
-	while (md_atomic_read(&mddev->recovery_sem.count) != 1)
+	while (sem_getcount(&mddev->recovery_sem) != 1)
 		schedule();
 
 	del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev)));
@@ -3219,7 +3219,7 @@
 		if (mddev->curr_resync) {
 			sz += status_resync (page+sz, mddev);
 		} else {
-			if (md_atomic_read(&mddev->resync_sem.count) != 1)
+			if (sem_getcount(&mddev->resync_sem) != 1)
 				sz += sprintf(page + sz, "	resync=DELAYED");
 		}
 		sz += sprintf(page + sz, "\n");
diff -urN linux-2.4.20-pre2/drivers/media/video/cpia.c linux-2.4.20-pre3/drivers/media/video/cpia.c
--- linux-2.4.20-pre2/drivers/media/video/cpia.c	Thu Oct 25 13:53:47 2001
+++ linux-2.4.20-pre3/drivers/media/video/cpia.c	Sat Aug 17 14:18:49 2002
@@ -56,7 +56,7 @@
 
 #ifdef MODULE
 MODULE_PARM(video_nr,"i");
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("video");
@@ -163,6 +163,7 @@
 #define COMMAND_SETAPCOR		0x1000
 #define COMMAND_SETFLICKERCTRL		0x2000
 #define COMMAND_SETVLOFFSET		0x4000
+#define COMMAND_SETLIGHTS		0x8000
 
 /* Developer's Guide Table 5 p 3-34
  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
@@ -178,50 +179,17 @@
  *
  * 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
- *
  **********************************************************************/
 
-/* 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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -229,12 +197,9 @@
 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);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -242,13 +207,9 @@
 	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)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -256,23 +217,16 @@
 
 static void rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	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)));
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -291,7 +245,7 @@
 	char *out = page;
 	int len, tmp;
 	struct cam_data *cam = data;
-	char tmpstr[20];
+	char tmpstr[29];
 
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
@@ -328,6 +282,13 @@
 	               cam->params.status.vpStatus);
 	out += sprintf(out, "error_code:               %#04x\n",
 	               cam->params.status.errorCode);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "button:                   %4d\n",
+		               cam->params.qx3.button);
+		out += sprintf(out, "cradled:                  %4d\n",
+		               cam->params.qx3.cradled);
+	}
 	out += sprintf(out, "video_size:               %s\n",
 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
@@ -392,16 +353,17 @@
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits gain to 2 */
-		sprintf(tmpstr, "%8d  %8d", 1, 2);
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
 	else
-		sprintf(tmpstr, "1,2,4,8");
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 
 	if (cam->params.exposure.gainMode == 0)
-		out += sprintf(out, "max_gain:                unknown  %18s"
-		               "  %8d\n", tmpstr, 2); 
+		out += sprintf(out, "max_gain:                unknown  %28s"
+		               "  powers of 2\n", tmpstr); 
 	else
-		out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
-		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+		out += sprintf(out, "max_gain:               %8d  %28s"
+			       "  1,2,4 or 8 \n",
+		               1<<(cam->params.exposure.gainMode-1), tmpstr);
 
 	switch(cam->params.exposure.expMode) {
 	case 1:
@@ -528,6 +490,15 @@
 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.toplight ? "on" : "off",
+			       "off", "on", "off");
+		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.bottomlight ? "on" : "off",
+			       "off", "on", "off");
+	}
 	
 	len = out - page;
 	len -= off;
@@ -541,18 +512,45 @@
 	return len;
 }
 
-static int cpia_write_proc(struct file *file, const char *buffer,
+static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
-	return -EINVAL;
-#if 0
 	struct cam_data *cam = data;
 	struct cam_params new_params;
+	char *page, *buffer;
 	int retval, find_colon;
 	int size = count;
-	unsigned long val;
+	unsigned long val = 0;
 	u32 command_flags = 0;
 	u8 new_mains;
+
+	/*
+	 * This code to copy from buf to page is shamelessly copied
+	 * from the comx driver
+	 */
+	if (count > PAGE_SIZE) {
+		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+	if(copy_from_user(page, buf, count))
+	{
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (page[count-1] == '\n')
+		page[count-1] = '\0';
+	else if (count < PAGE_SIZE)
+		page[count] = '\0';
+	else if (page[count]) {
+		retval = -EINVAL;
+		goto out;
+	}
+	
+	buffer = page;
 	
 	if (down_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
@@ -1210,6 +1208,22 @@
 					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("toplight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.toplight = 1;
+			else if (!retval && MATCH("off"))
+				new_params.qx3.toplight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
+		} else if (MATCH("bottomlight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.bottomlight = 1;
+			else if (!retval && MATCH("off"))  
+				new_params.qx3.bottomlight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
 		} else {
 			DBG("No match found\n");
 			retval = -EINVAL;
@@ -1221,7 +1235,10 @@
 				++buffer;
 			}
 			if (count) {
-				if (*buffer != '\n' && *buffer != ';')
+				if (*buffer == '\0' && count != 1)
+					retval = -EINVAL;
+				else if (*buffer != '\n' && *buffer != ';' &&
+					 *buffer != '\0')
 					retval = -EINVAL;
 				else {
 					--count;
@@ -1255,8 +1272,9 @@
 	
 	up(&cam->param_lock);
 	
+out:
+	free_page((unsigned long)page);
 	return retval;
-#endif
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
@@ -1276,7 +1294,12 @@
 	ent->data = cam;
 	ent->read_proc = cpia_read_proc;
 	ent->write_proc = cpia_write_proc;
-	ent->size = 3626;
+	/* 
+	   size of the proc entry is 3672 bytes for the standard webcam;
+ 	   the extra features of the QX3 microscope add 188 bytes.
+	   (we have not yet probed the camera to see which type it is).
+	*/
+	ent->size = 3672 + 188;
 	cam->proc_entry = ent;
 }
 
@@ -1570,6 +1593,10 @@
 		down(&cam->param_lock);
 		datasize=8;
 		break;
+	case CPIA_COMMAND_ReadMCPorts: 
+	case CPIA_COMMAND_ReadVCRegs:
+		datasize = 4;
+		break;
 	default:
 		datasize=0;
 		break;
@@ -1667,6 +1694,22 @@
 			  }
 			up(&cam->param_lock);
 			break;
+
+		case CPIA_COMMAND_ReadMCPorts: 
+			if (!cam->params.qx3.qx3_detected) 
+				break;
+			/* test button press */ 
+			cam->params.qx3.button = ((data[1] & 0x02) == 0);
+			if (cam->params.qx3.button) {
+				/* button pressed - unlock the latch */
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+			}
+
+			/* test whether microscope is cradled */
+			cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+			break;
+
 		default:
 			break;
 		}
@@ -1826,6 +1869,7 @@
 {
 	switch(fmt) {
 	case VIDEO_PALETTE_GREY:
+		return count;
 	case VIDEO_PALETTE_RGB555:
 	case VIDEO_PALETTE_RGB565:
 	case VIDEO_PALETTE_YUV422:
@@ -2106,6 +2150,13 @@
 	if (cam->cmd_queue & COMMAND_RESUME)
 		init_stream_cap(cam);
 
+	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
+		int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+		int p2 = (cam->params.qx3.toplight == 0) << 3;
+		do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+		do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+	}
+
 	up(&cam->param_lock);
 	cam->cmd_queue = COMMAND_NONE;
 	return;
@@ -2182,9 +2233,10 @@
 		/* camera idle now so dispatch queued commands */
 		dispatch_commands(cam);
 
-		/* Update our knowledge of the camera state - FIXME: necessary? */
+		/* Update our knowledge of the camera state */
 		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
 		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
@@ -2396,7 +2448,11 @@
 	get_version_information(cam);
 	if (cam->params.version.firmwareVersion != 1)
 		return -ENODEV;
-	
+
+	/* set QX3 detected flag */
+	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+					cam->params.pnpID.product == 0x0001);
+
 	/* The fatal error checking should be done after
 	 * the camera powers up (developer's guide p 3-38) */
 
@@ -2526,7 +2582,7 @@
 		/* GotoLoPower */
 		goto_low_power(cam);
 
-		/* Update the camera ststus */
+		/* Update the camera status */
 		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
 
 		/* cleanup internal state stuff */
@@ -2566,7 +2622,7 @@
 {
 	struct cam_data *cam = dev->priv;
 
-	/* make this _really_ smp and multithredi-safe */
+	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
 
@@ -2793,7 +2849,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		// FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
 		up(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
@@ -2835,10 +2890,8 @@
 			retval = -EFAULT;
 			break;
 		}
-#if 1
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
-#endif
 		if (vm.frame<0||vm.frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
@@ -2848,6 +2901,8 @@
 		cam->vp.palette = vm.format;
 		switch(vm.format) {
 		case VIDEO_PALETTE_GREY:
+			cam->vp.depth=8;
+			break;
 		case VIDEO_PALETTE_RGB555:
 		case VIDEO_PALETTE_RGB565:
 		case VIDEO_PALETTE_YUV422:
@@ -2880,10 +2935,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 			dispatch_commands(cam);
 		}
-#if 0
-		DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
-		    cam->vw.width, cam->vw.height);
-#endif
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
 		retval = capture_frame(cam, &vm);
@@ -3035,7 +3086,7 @@
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_CPIA,      /* FIXME */
+	hardware:	VID_HARDWARE_CPIA,
 	open:		cpia_open,
 	close:		cpia_close,
 	read:		cpia_read,
@@ -3100,8 +3151,8 @@
 	cam->params.sensorFps.divisor = 1;
 	cam->params.sensorFps.baserate = 1;
 	
-	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
-	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
 	
 	cam->params.format.subSample = SUBSAMPLE_422;
 	cam->params.format.yuvOrder = YUVORDER_YUYV;
@@ -3109,8 +3160,14 @@
 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
 	cam->params.compressionTarget.frTargeting =
 		CPIA_COMPRESSION_TARGET_QUALITY;
-	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
-	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+
+	cam->params.qx3.qx3_detected = 0;
+	cam->params.qx3.toplight = 0;
+	cam->params.qx3.bottomlight = 0;
+	cam->params.qx3.button = 0;
+	cam->params.qx3.cradled = 0;
 
 	cam->video_size = VIDEOSIZE_CIF;
 	
@@ -3119,8 +3176,8 @@
 	cam->vp.brightness = 32768;  /* 50% */
 	cam->vp.contrast = 32768;    /* 50% */
 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
-	cam->vp.depth = 0;           /* FIXME: to be set by user? */
-	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+	cam->vp.depth = 24;          /* to be set by user */
+	cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
 
 	cam->vw.x = 0;
 	cam->vw.y = 0;
@@ -3209,12 +3266,6 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
-/* Eh? Feeling happy? - jerdfelt */
-/*
-	camera->ops->open(camera->lowlevel_data);
-	camera->ops->close(camera->lowlevel_data);
-*/
-	
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,
diff -urN linux-2.4.20-pre2/drivers/media/video/cpia.h linux-2.4.20-pre3/drivers/media/video/cpia.h
--- linux-2.4.20-pre2/drivers/media/video/cpia.h	Thu Oct 25 13:53:47 2001
+++ linux-2.4.20-pre3/drivers/media/video/cpia.h	Sat Aug 17 14:18:49 2002
@@ -27,12 +27,12 @@
  */
 
 #define CPIA_MAJ_VER	0
-#define CPIA_MIN_VER    7
-#define CPIA_PATCH_VER	4
+#define CPIA_MIN_VER    8
+#define CPIA_PATCH_VER	1
 
 #define CPIA_PP_MAJ_VER       0
-#define CPIA_PP_MIN_VER       7
-#define CPIA_PP_PATCH_VER     4
+#define CPIA_PP_MIN_VER       8
+#define CPIA_PP_PATCH_VER     1
 
 #define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
 #define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
@@ -204,6 +204,13 @@
 		u8 subSample;
 		u8 yuvOrder;
 	} format;
+        struct {                        /* Intel QX3 specific data */
+                u8 qx3_detected;        /* a QX3 is present */
+                u8 toplight;            /* top light lit , R/W */
+                u8 bottomlight;         /* bottom light lit, R/W */
+                u8 button;              /* snapshot button pressed (R/O) */
+                u8 cradled;             /* microscope is in cradle (R/O) */
+        } qx3;
 	struct {
 		u8 colStart;		/* skip first 8*colStart pixels */
 		u8 colEnd;		/* finish at 8*colEnd pixels */
@@ -393,29 +400,6 @@
       (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
         (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
 
-#define ADD_TO_LIST(l, drv) \
-  {\
-    lock_kernel();\
-    (drv)->next = l;\
-    (drv)->previous = &(l);\
-    (l) = drv;\
-    unlock_kernel();\
-  } while(0)
-
-#define REMOVE_FROM_LIST(drv) \
-  {\
-    if ((drv)->previous != NULL) {\
-      lock_kernel();\
-      if ((drv)->next != NULL)\
-        (drv)->next->previous = (drv)->previous;\
-      *((drv)->previous) = (drv)->next;\
-      (drv)->previous = NULL;\
-      (drv)->next = NULL;\
-      unlock_kernel();\
-    }\
-  } while (0)
-
-
 static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv)
 {
 	drv->next = l;
@@ -423,7 +407,6 @@
 	l = drv;
 }
 
-
 static inline void cpia_remove_from_list(struct cam_data* drv)
 {
 	if (drv->previous != NULL) {
@@ -435,7 +418,6 @@
 	}
 }
 
-
 #endif /* __KERNEL__ */
 
 #endif /* cpia_h */
diff -urN linux-2.4.20-pre2/drivers/media/video/cpia_pp.c linux-2.4.20-pre3/drivers/media/video/cpia_pp.c
--- linux-2.4.20-pre2/drivers/media/video/cpia_pp.c	Thu Oct 25 13:53:47 2001
+++ linux-2.4.20-pre3/drivers/media/video/cpia_pp.c	Sat Aug 17 14:18:49 2002
@@ -4,7 +4,7 @@
  * Supports CPiA based parallel port Video Camera's.
  *
  * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
- * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
  * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -340,17 +340,6 @@
 	return 0;
 }
 
-static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
-{
-	int bytes_read, new_bytes;
-	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
-		new_bytes = parport_read(port, buffer+bytes_read,
-			                 len-bytes_read);
-		if(new_bytes < 0) break;
-	}
-	return bytes_read;
-}
-
 /****************************************************************************
  *
  *  cpia_pp_streamRead
@@ -360,7 +349,7 @@
 {
 	struct pp_cam_entry *cam = privdata;
 	int read_bytes = 0;
-	int i, endseen, block_size, new_bytes;
+	int i, endseen;
 
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
@@ -389,34 +378,25 @@
 			return -EIO;
 		}
 	}
+	read_bytes = parport_read(cam->port, buffer, CPIA_MAX_IMAGE_SIZE );
+
+	EndTransferMode(cam);
+	DBG("read %d bytes\n", read_bytes);
+	if( read_bytes<0) return -EIO;
 	endseen = 0;
-	block_size = PARPORT_CHUNK_SIZE;
-	while( !cam->image_complete ) {
-		if(current->need_resched)  schedule();
-		
-		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
-		if( new_bytes <= 0 ) {
-			break;
-		}
-		i=-1;
-		while(++i<new_bytes && endseen<4) {
-	        	if(*buffer==EOI) {
-	                	endseen++;
-	                } else {
-	                	endseen=0;
-	                }
-			buffer++;
-		}
-		read_bytes += i;
-		if( endseen==4 ) {
-			cam->image_complete=1;
-			break;
-		}
-		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
-			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
-		}
+	endseen = 0;
+	for( i=0; i<read_bytes && endseen<4; i++ ) {
+	  if( *buffer==EOI ) {
+	    endseen++;
+	  } else {
+	    endseen=0;
+	  }
+	  buffer++;
+	}
+	if( endseen>3 ) {
+	  cam->image_complete=1;
+	  DBG("endseen at %d bytes\n", i);
 	}
-	EndTransferMode(cam);
 	return cam->image_complete ? read_bytes : -EIO;
 }
 
@@ -716,15 +696,6 @@
 
 static int __init cpia_pp_setup(char *str)
 {
-#if 0
-	/* Is this only a 2.2ism? -jerdfelt */
-	if (!str) {
-		if (ints[0] == 0 || ints[1] == 0) {
-			/* disable driver on "cpia_pp=" or "cpia_pp=0" */
-			parport_nr[0] = PPCPIA_PARPORT_OFF;
-		}
-	} else
-#endif
 	if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str + 7, NULL, 10);
 		if (parport_ptr < PARPORT_MAX) {
diff -urN linux-2.4.20-pre2/drivers/media/video/cpia_usb.c linux-2.4.20-pre3/drivers/media/video/cpia_usb.c
--- linux-2.4.20-pre2/drivers/media/video/cpia_usb.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/media/video/cpia_usb.c	Sat Aug 17 14:18:49 2002
@@ -266,14 +266,16 @@
 
 error_urb1:		/* free urb 1 */
 	usb_free_urb(ucpia->sbuf[1].urb);
-
+	ucpia->sbuf[1].urb = NULL;
 error_urb0:		/* free urb 0 */
 	usb_free_urb(ucpia->sbuf[0].urb);
-
+	ucpia->sbuf[0].urb = NULL;
 error_1:
 	kfree (ucpia->sbuf[1].data);
+	ucpia->sbuf[1].data = NULL;
 error_0:
 	kfree (ucpia->sbuf[0].data);
+	ucpia->sbuf[0].data = NULL;
 	
 	return retval;
 }
@@ -620,8 +622,10 @@
 		ucpia->buffers[0] = NULL;
 	}
 
-	if (!ucpia->open)
+	if (!ucpia->open) {
 		kfree(ucpia);
+		cam->lowlevel_data = NULL;
+	}
 }
 
 static int __init usb_cpia_init(void)
diff -urN linux-2.4.20-pre2/drivers/media/video/zr36067.c linux-2.4.20-pre3/drivers/media/video/zr36067.c
--- linux-2.4.20-pre2/drivers/media/video/zr36067.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/media/video/zr36067.c	Sat Aug 17 14:18:49 2002
@@ -1417,7 +1417,7 @@
 		zr36060_sleep(zr, 0);
 		post_office_write(zr, 3, 0, 0);
 		udelay(2);
-	default:
+	default:;
 	}
 	return 0;
 }
@@ -4208,6 +4208,7 @@
 
 			/* sleep 1 second */
 
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ);
 
 			/* Get status of video decoder */
diff -urN linux-2.4.20-pre2/drivers/message/fusion/mptbase.c linux-2.4.20-pre3/drivers/message/fusion/mptbase.c
--- linux-2.4.20-pre2/drivers/message/fusion/mptbase.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/message/fusion/mptbase.c	Sat Aug 17 14:18:49 2002
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.120 2002/06/27 13:53:27 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -437,8 +437,9 @@
 			pa = 0;					/* No reply flush! */
 		}
 
+#ifdef MPT_DEBUG_IRQ
 		if ((int)ioc->chip_type > (int)FC929) {
-			/* Verify mf, mf are reasonable.
+			/* Verify mf, mr are reasonable.
 			 */
 			if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
 				|| (mf < ioc->req_frames)) ) {
@@ -464,6 +465,7 @@
 				freeme = 0;
 			}
 		}
+#endif
 
 		/*  Check for (valid) IO callback!  */
 		if (cb_idx) {
diff -urN linux-2.4.20-pre2/drivers/message/fusion/mptbase.h linux-2.4.20-pre3/drivers/message/fusion/mptbase.h
--- linux-2.4.20-pre2/drivers/message/fusion/mptbase.h	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/message/fusion/mptbase.h	Sat Aug 17 14:18:50 2002
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.127 2002/07/09 13:30:36 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.131 2002/07/31 18:55:11 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.01.07"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.01.07"
+#define MPT_LINUX_VERSION_COMMON	"2.01.10"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.01.10"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -515,7 +515,7 @@
 #define MPT_SCSICFG_NEGOTIATE		0x01	/* Negotiate on next IO */
 #define MPT_SCSICFG_NEED_DV		0x02	/* Schedule DV */
 #define MPT_SCSICFG_DV_PENDING		0x04	/* DV on this physical id pending */
-#define MPT_SCSICFG_DV_DONE		0x08	/* DV on this physical id complete */
+#define MPT_SCSICFG_DV_NOT_DONE		0x08	/* DV has not been performed */
 #define MPT_SCSICFG_BLK_NEGO		0x10	/* WriteSDP1 with WDTR and SDTR disabled */
 
 						/* Args passed to writeSDP1: */
@@ -527,6 +527,7 @@
 	int		*nvram;			/* table of device NVRAM values */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
+	u8		 iocntr[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
 	u8		 maxSyncOffset;		/* 0 if async */
diff -urN linux-2.4.20-pre2/drivers/message/fusion/mptctl.c linux-2.4.20-pre3/drivers/message/fusion/mptctl.c
--- linux-2.4.20-pre2/drivers/message/fusion/mptctl.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/message/fusion/mptctl.c	Sat Aug 17 14:18:50 2002
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.55 2002/06/20 13:28:16 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.58 2002/07/31 18:55:12 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -637,8 +637,8 @@
 	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnumX);
+		dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -708,9 +708,9 @@
 	}
 
 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
-				__FILE__, __LINE__, krinfo.hdr.iocnum);
-		return -ENXIO; /* (-6) No such device or address */
+		dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+				__FILE__, __LINE__, krinfo.hdr.iocnum));
+		return -ENODEV; /* (-6) No such device or address */
 	}
 
 	if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
@@ -816,9 +816,9 @@
 	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
 
 	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
-		printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
-				__FILE__, __LINE__, ioc);
-		return -ENXIO; /* (-6) No such device or address */
+		dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+				__FILE__, __LINE__, ioc));
+		return -ENODEV; /* (-6) No such device or address */
 	}
 
 	/*  Valid device. Get a message frame and construct the FW download message.
@@ -1252,8 +1252,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1379,8 +1379,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1510,8 +1510,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1568,8 +1568,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1606,8 +1606,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1654,8 +1654,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1708,8 +1708,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1794,8 +1794,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -1842,8 +1842,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 	if (!ioc->ioctl) {
@@ -1948,10 +1948,6 @@
 
 			if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
 				qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
-			else {
-				rc = -EPERM;
-				goto done_free_mem;
-			}
 
 			/* Have the IOCTL driver set the direction based
 			 * on the dataOutSize (ordering issue with Sparc).
@@ -2393,8 +2389,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnumX);
+		dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -2466,8 +2462,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2567,8 +2563,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2631,8 +2627,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2687,8 +2683,8 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2790,8 +2786,8 @@
 	iocnumX = karg.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum);
+		dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
 
@@ -2920,12 +2916,12 @@
 
 static struct file_operations mptctl_fops = {
 	owner_THIS_MODULE
-	llseek:		no_llseek,
-	read:		mptctl_read,
-	write:		mptctl_write,
-	ioctl:		mptctl_ioctl,
-	open:		mptctl_open,
-	release:	mptctl_release,
+	.llseek =	no_llseek,
+	.read =		mptctl_read,
+	.write =	mptctl_write,
+	.ioctl =	mptctl_ioctl,
+	.open =		mptctl_open,
+	.release =	mptctl_release,
 };
 
 static struct miscdevice mptctl_miscdev = {
@@ -2975,8 +2971,8 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -3015,8 +3011,8 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
@@ -3072,8 +3068,8 @@
 	iocnumX = karg32.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
-				__LINE__, iocnumX);
+		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX));
 		return -ENODEV;
 	}
 
diff -urN linux-2.4.20-pre2/drivers/message/fusion/mptscsih.c linux-2.4.20-pre3/drivers/message/fusion/mptscsih.c
--- linux-2.4.20-pre2/drivers/message/fusion/mptscsih.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/message/fusion/mptscsih.c	Sat Aug 17 14:18:50 2002
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.97 2002/07/03 13:11:01 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.100 2002/07/31 18:55:12 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -183,7 +183,7 @@
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
-static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data);
+static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
 static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
@@ -226,11 +226,11 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
 static struct proc_dir_entry proc_mpt_scsihost =
 {
-	low_ino:	PROC_SCSI_MPT,
-	namelen:	8,
-	name:		"mptscsih",
-	mode:		S_IFDIR | S_IRUGO | S_IXUGO,
-	nlink:		2,
+	.low_ino =	PROC_SCSI_MPT,
+	.namelen =	8,
+	.name =		"mptscsih",
+	.mode =		S_IFDIR | S_IRUGO | S_IXUGO,
+	.nlink =	2,
 };
 #endif
 
@@ -323,8 +323,8 @@
 		return 1;
 	}
 
-	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n",
-			ioc->name, mf, mr, sc));
+	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+			ioc->name, mf, mr, sc, req_idx));
 
 	atomic_dec(&queue_depth);
 
@@ -332,6 +332,14 @@
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	if (hd->is_spi) {
+		u32 qtag = le32_to_cpu(pScsiReq->Control);
+		if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED)
+			hd->ioc->spi_data.iocntr[sc->target]--;
+	}
+#endif
+
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 
@@ -351,9 +359,6 @@
 			}
 		}
 		clear_sense_flag(hd, pScsiReq);
-
-		if (hd->is_spi)
-			mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -484,9 +489,6 @@
 						sc->buffer,
 						xfer_cnt);
 			}
-
-			if (hd->is_spi)
-				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
@@ -568,9 +570,6 @@
 						sc->buffer,
 						xfer_cnt);
 			}
-
-			if (hd->is_spi)
-				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 			break;
 
 		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
@@ -947,6 +946,12 @@
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
 	}
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	/* Clear untagged counting array */
+	for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+		hd->ioc->spi_data.iocntr[ii] = 0;
+#endif
+
 	return;
 }
 
@@ -1435,7 +1440,11 @@
 					hd->ioc->spi_data.forceDv = 0;
 					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
 						hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
-
+	
+					if (hd->negoNvram == 0) {
+						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+							hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
+					}
 
 					ddvprintk((MYIOC_s_INFO_FMT
 						"dv %x width %x factor %x \n",
@@ -2041,17 +2050,25 @@
 					mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
 					issueCmd = 0;
 				}
+
+				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)
+					hd->ioc->spi_data.iocntr[target]++;
+
+				/* Set the DV flags.
+				 */
+				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+					mptscsih_set_dvflags(hd, pScsiReq);
 #endif
 			}
 		}
 
 		if (issueCmd) {
 			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n",
-					hd->ioc->name, SCpnt));
+			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+					hd->ioc->name, SCpnt, mf, my_idx));
 		} else {
-			ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n",
-					hd->ioc->name, SCpnt));
+			ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
+					hd->ioc->name, SCpnt, my_idx));
 			/* Place this command on the pendingQ if possible */
 			spin_lock_irqsave(&hd->freedoneQlock, flags);
 			if (!Q_IS_EMPTY(&hd->freeQ)) {
@@ -3683,10 +3700,25 @@
  *     0 = _DIR_NONE	changed to SCSI_DATA_NONE (3)
  *    -1 = _DATA_IN	changed to SCSI_DATA_READ (2)
  * If the direction is unknown, fall through to original code.
+ *
+ * Mid-layer bug fix(): sg interface generates the wrong data 
+ * direction in some cases. Set the direction the hard way for 
+ * the most common commands.
  */
 static int
 mptscsih_io_direction(Scsi_Cmnd *cmd)
 {
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:		
+	case WRITE_10:		
+		return SCSI_DATA_WRITE;
+		break;
+	case READ_6:		
+	case READ_10:		
+		return SCSI_DATA_READ;
+		break;
+	}
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
 		return cmd->sc_data_direction;
@@ -3898,7 +3930,7 @@
 	MPT_FRAME_HDR	*mf = NULL;
 	MPT_FRAME_HDR	*cmdMfPtr = NULL;
 
-	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name));
+	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
 	cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
 	spin_lock_irqsave(&hd->freedoneQlock, flags);
 	if (!Q_IS_EMPTY(&hd->pendingQ)) {
@@ -3938,7 +3970,7 @@
 
 	/* Flush the pendingQ.
 	 */
-	ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name));
+	ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name));
 	while (1) {
 		spin_lock_irqsave(&hd->freedoneQlock, flags);
 		if (Q_IS_EMPTY(&hd->pendingQ)) {
@@ -3966,8 +3998,15 @@
 		}
 
 		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-		ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n",
-				hd->ioc->name, mf));
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+		{
+			u16		 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+			Scsi_Cmnd	*sc = hd->ScsiLookup[req_idx];
+			printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n",
+					hd->ioc->name, sc, req_idx, mf);
+		}
+#endif
 	}
 
 	return;
@@ -4177,7 +4216,7 @@
 
 					while (numPDisk) {
 						if (physDiskNum == pPDisk->PhysDiskNum) {
-							pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV;
+							pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
 							pSpi->forceDv = MPT_SCSICFG_NEED_DV;
 							ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
 							break;
@@ -4612,6 +4651,20 @@
 		return 0;
 	}
 
+	/* Prevent the system from continually writing to the log
+	 * if a medium is not found: 02 3A 00
+	 * Changer issues: TUR, Read Capacity, Table of Contents continually
+	 */
+	if (sk==SK_NOT_READY && asc==0x3A) {
+		if (ioop->cdbPtr == NULL) {
+			return 0;
+		} else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
+			(ioop->cdbPtr[0] == CMD_ReadCapacity) || 
+			(ioop->cdbPtr[0] == 0x43)) {
+			return 0;
+		}
+	}
+
 	/*
 	 *  Protect ourselves...
 	 */
@@ -4746,6 +4799,14 @@
 				mptscsih_setTargetNegoParms(hd, vdev, data[56]);
 			else
 				mptscsih_setTargetNegoParms(hd, vdev, 0);
+
+			/* If LUN 0, tape and have not done DV, set the DV flag.
+			 */
+			if ((lun == 0) && ((data[0] & 0x1F) == 0x01)) {
+				ScsiCfgData *pSpi = &hd->ioc->spi_data;
+				if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
+					pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
+			}
 		}
 
 		/* Is LUN supported? If so, upper 3 bits will be 0
@@ -4915,43 +4976,39 @@
 	return;
 }
 
-/* 
- * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks) 
- * or Mode Sense (cdroms). Tapes, key off of Inquiry command.
+ * or Mode Sense (cdroms). 
+ *
+ * Tapes, initTarget will set this flag on completion of Inquiry command.
+ * Called only if DV_NOT_DONE flag is set
  */
-static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data)
+static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
 {
-	u8 cmd = pReq->CDB[0];
+	u8 cmd;
 	
-	if (pReq->LUN[1] != 0)
+	if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
 		return;
 
-	if (hd->negoNvram != 0)
-		return;
+	cmd = pReq->CDB[0];
 
-	if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || 
-		((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) {
-		u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID];
-		if (!(dvStatus & MPT_SCSICFG_DV_DONE)) {
-			ScsiCfgData *pSpi = &hd->ioc->spi_data;
-			if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
-				/* Set NEED_DV for all hidden disks
-				 */
-				Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
-				int		numPDisk = pSpi->pIocPg3->NumPhysDisks;
-				
-				while (numPDisk) {
-					pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
-					ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
-					pPDisk++;
-					numPDisk--;
-				}
+	if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
+		ScsiCfgData *pSpi = &hd->ioc->spi_data;
+		if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
+			/* Set NEED_DV for all hidden disks
+			 */
+			Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
+			int		numPDisk = pSpi->pIocPg3->NumPhysDisks;
+
+			while (numPDisk) {
+				pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+				ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+				pPDisk++;
+				numPDisk--;
 			}
-			pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
-			ddvtprintk(("NEED_DV set for visible disk id %d\n", 
-					pReq->TargetID));
-		};
+		}
+		pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
+		ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
 	}
 }
 
@@ -5052,6 +5109,7 @@
 	u8			 offset;
 	u8			 bus = 0;
 	u8			 negoFlags;
+	u8			 maxwidth, maxoffset, maxfactor;
 
 	if (ioc->spi_data.sdp1length == 0)
 		return 0;
@@ -5065,48 +5123,53 @@
 	}
 
 	for (; id <= maxid; id++) {
+
 		if (id == ioc->pfacts[portnum].PortSCSIID)
 			continue;
 
-		if (flags & MPT_SCSICFG_USE_NVRAM) {
-			/* Use NVRAM, adapter maximums and target settings.
-			 * Data over-riden by target structure information, if present
-			 */
-			width = ioc->spi_data.maxBusWidth;
-			offset = ioc->spi_data.maxSyncOffset;
-			factor = ioc->spi_data.minSyncFactor;
-			if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
-				nvram = ioc->spi_data.nvram[id];
-
-				if (width)
-					width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
-
-				if (offset > 0) {
-					factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
-					if (factor == 0) {
-						/* Key for async */
-						factor = MPT_ASYNC;
-						offset = 0;
-					} else if (factor < ioc->spi_data.minSyncFactor) {
-						factor = ioc->spi_data.minSyncFactor;
-					}
-				} else
-					factor = MPT_ASYNC;
-			}
+		/* Use NVRAM to get adapter and target maximums
+		 * Data over-riden by target structure information, if present
+		 */
+		maxwidth = ioc->spi_data.maxBusWidth;
+		maxoffset = ioc->spi_data.maxSyncOffset;
+		maxfactor = ioc->spi_data.minSyncFactor;
+		if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			nvram = ioc->spi_data.nvram[id];
+
+			if (maxwidth)
+				maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+			if (maxoffset > 0) {
+				maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+				if (maxfactor == 0) {
+					/* Key for async */
+					maxfactor = MPT_ASYNC;
+					maxoffset = 0;
+				} else if (maxfactor < ioc->spi_data.minSyncFactor) {
+					maxfactor = ioc->spi_data.minSyncFactor;
+				}
+			} else
+				maxfactor = MPT_ASYNC;
+		}
 
-			/* Set the negotiation flags.
-			 */
-			negoFlags = ioc->spi_data.noQas;
-			if (!width)
-				negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
-	
-			if (!offset)
-				negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+		/* Set the negotiation flags.
+		 */
+		negoFlags = ioc->spi_data.noQas;
+		if (!maxwidth)
+			negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+		if (!maxoffset)
+			negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+		if (flags & MPT_SCSICFG_USE_NVRAM) {
+			width = maxwidth;
+			factor = maxfactor;
+			offset = maxoffset;
 		} else {
 			width = 0;
 			factor = MPT_ASYNC;
 			offset = 0;
-			negoFlags = 0;
+			//negoFlags = 0;
 			//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
 		}
 
@@ -5135,6 +5198,10 @@
 			return -EAGAIN;
 		}
 
+		ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
+			hd->ioc->name, mf, id, requested, configuration));
+
+
 		/* Set the request and the data pointers.
 		 * Request takes: 36 bytes (32 bit SGE)
 		 * SCSI Device Page 1 requires 16 bytes
@@ -5291,13 +5358,13 @@
 	pReq = (SCSIIORequest_t *) mf;
 
 	if (mf != hd->cmdPtr) {
-		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n",
-				hd->ioc->name, (void *)mf, (void *) hd->cmdPtr);
+		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
+				hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
 	}
 	hd->cmdPtr = NULL;
 
-	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n",
-			hd->ioc->name, mf, mr));
+	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+			hd->ioc->name, mf, mr, req_idx));
 
 	atomic_dec(&queue_depth);
 
@@ -5965,7 +6032,6 @@
 	unsigned long		 flags;
 	int 			 id, maxid, dvStatus, did;
 	int			 ii, isPhysDisk;
-	u8			 oldQas;
 
 	spin_lock_irqsave(&dvtaskQ_lock, flags);
 	dvtaskQ_active = 1;
@@ -6011,7 +6077,6 @@
 			maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
 
 			for (id = 0; id < maxid; id++) {
-				oldQas = hd->ioc->spi_data.noQas;
 				spin_lock_irqsave(&dvtaskQ_lock, flags);
 				if (dvtaskQ_release) {
 					dvtaskQ_active = 0;
@@ -6022,8 +6087,25 @@
 				dvStatus = hd->ioc->spi_data.dvStatus[id];
 
 				if (dvStatus & MPT_SCSICFG_NEED_DV) {
+					VirtDevice *pTarget = hd->Targets[id];
+					did++;
+					if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){
+						if (hd->ioc->spi_data.iocntr[id] == 0) {
+							hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+						} else {
+							/* Wait until not busy
+							 */
+							ddvtprintk((MYIOC_s_NOTE_FMT 
+							" DV Wait: %d untagged and busy. cntr %d\n",
+							ioc->name, id, 
+							hd->ioc->spi_data.iocntr[id]));
+							continue;
+						}
+					} else {
+						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+					}
+
 
-					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
 					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
 
 					set_current_state(TASK_INTERRUPTIBLE);
@@ -6043,9 +6125,8 @@
 					}
 
 					mptscsih_doDv(hd, 0, id);
-					did++;
-					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE;
-					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+
+					hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
 
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
@@ -6060,7 +6141,7 @@
 					 */
 					post_pendingQ_commands(hd);
 
-					if ((!oldQas) && (hd->ioc->spi_data.noQas))
+					if (hd->ioc->spi_data.noQas)
 						mptscsih_qas_check(hd);
 				}
 			}
@@ -6099,27 +6180,25 @@
 {
 	VirtDevice *pTarget = NULL;
 	int ii;
-	int change = 0;
 
 	if (hd->Targets == NULL)
 		return;
 
 	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
-		change = 0;
+		if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
+			continue;
+
 		pTarget = hd->Targets[ii];
 
 		if ((pTarget != NULL) && (!pTarget->raidVolume)) {
 			if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
-				change = 1;
 				pTarget->negoFlags |= hd->ioc->spi_data.noQas;
+				mptscsih_writeSDP1(hd, 0, ii, 0);
 			}
 		} else {
 			if (mptscsih_is_phys_disk(hd->ioc, ii) == 1)
-				change = 1;
+				mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
 		}
-
-		if ((change) && (hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_DONE))
-			mptscsih_writeSDP1(hd, 0, ii, 0);
 	}
 	return;
 }
@@ -6407,6 +6486,7 @@
 					cfg.physAddr = cfg0_dma_addr;
 					cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 					cfg.dir = 0;
+
 					if (mpt_config(hd->ioc, &cfg) != 0)
 						goto target_done;
 
diff -urN linux-2.4.20-pre2/drivers/net/Config.in linux-2.4.20-pre3/drivers/net/Config.in
--- linux-2.4.20-pre2/drivers/net/Config.in	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/net/Config.in	Sat Aug 17 14:18:50 2002
@@ -149,9 +149,9 @@
       tristate '  IBM LAN Adapter/A support' CONFIG_IBMLANA
    fi
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-     bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+      bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    else
-     define_bool CONFIG_NET_PCI n
+      define_bool CONFIG_NET_PCI n
    fi
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
@@ -241,7 +241,7 @@
 dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
 dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI
 dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
-dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI
+dep_tristate 'National Semiconductor DP83820 support' CONFIG_NS83820 $CONFIG_PCI
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 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
diff -urN linux-2.4.20-pre2/drivers/net/atarilance.c linux-2.4.20-pre3/drivers/net/atarilance.c
--- linux-2.4.20-pre2/drivers/net/atarilance.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/net/atarilance.c	Tue Oct 16 21:56:29 2001
@@ -546,11 +546,8 @@
 	if (lp->cardtype == PAM_CARD ||
 		memaddr == (unsigned short *)0xffe00000) {
 		/* PAMs card and Riebl on ST use level 5 autovector */
-		if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
-		            "PAM/Riebl-ST Ethernet", dev)) { 
-			printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
-			return( 0 );
-		}
+		request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
+		            "PAM/Riebl-ST Ethernet", dev);
 		dev->irq = (unsigned short)IRQ_AUTO_5;
 	}
 	else {
@@ -563,11 +560,8 @@
 			printk( "Lance: request for VME interrupt failed\n" );
 			return( 0 );
 		}
-		if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
-		            "Riebl-VME Ethernet", dev)) {
-			printk( "Lance: request for irq %d failed\n", irq );
-			return( 0 );
-		}
+		request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
+		            "Riebl-VME Ethernet", dev);
 		dev->irq = irq;
 	}
 
diff -urN linux-2.4.20-pre2/drivers/net/depca.c linux-2.4.20-pre3/drivers/net/depca.c
--- linux-2.4.20-pre2/drivers/net/depca.c	Sat Aug 17 14:18:18 2002
+++ linux-2.4.20-pre3/drivers/net/depca.c	Sat Aug 17 14:18:50 2002
@@ -1347,8 +1347,7 @@
 				   ** If the MCA configuration says the card should be here,
 				   ** it really should be here.
 				 */
-				printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
-responding.\n", dev->name, iobase);
+				printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase);
 			}
 
 			if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
@@ -1970,7 +1969,7 @@
 	case DEPCA_SET_MCA:	/* Set a multicast address */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (ioc->len >= HASH_TABLE_LEN || ioc->len < 0)
+		if (ioc->len >= HASH_TABLE_LEN)
 			return -EINVAL;
 		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
 			return -EFAULT;
diff -urN linux-2.4.20-pre2/drivers/net/eepro.c linux-2.4.20-pre3/drivers/net/eepro.c
--- linux-2.4.20-pre2/drivers/net/eepro.c	Sat Aug 17 14:18:19 2002
+++ linux-2.4.20-pre3/drivers/net/eepro.c	Sat Aug 17 14:18:51 2002
@@ -732,27 +732,27 @@
 		goto exit;
 	}
 
-		/* We seem to have the 82595 signature, let's
-		   play with its counter (last 2 bits of
-		   register 2 of bank 0) to be sure. */
+	/* We seem to have the 82595 signature, let's
+	   play with its counter (last 2 bits of
+	   register 2 of bank 0) to be sure. */
 
-		counter = (id & R_ROBIN_BITS);
+	counter = (id & R_ROBIN_BITS);
 
 	if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) {
 		retval = -ENODEV;
 		goto exit;
 	}
 
-			/* Initialize the device structure */
-			dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+	/* Initialize the device structure */
+	dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
 	if (!dev->priv) {
 		retval = -ENOMEM;
 		goto exit;
 	}
 
-			memset(dev->priv, 0, sizeof(struct eepro_local));
+	memset(dev->priv, 0, sizeof(struct eepro_local));
 
-			lp = (struct eepro_local *)dev->priv;
+	lp = (struct eepro_local *)dev->priv;
 
 	/* default values */
 	lp->eepro = 0;
@@ -761,37 +761,37 @@
 	lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
 	lp->eeprom_reg = EEPROM_REG_PRO;
 
-			/* Now, get the ethernet hardware address from
-			   the EEPROM */
-			station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
-			/* FIXME - find another way to know that we've found
-			 * an Etherexpress 10
-			 */
-			if (station_addr[0] == 0x0000 ||
-			    station_addr[0] == 0xffff) {
-				lp->eepro = LAN595FX_10ISA;
+	/* Now, get the ethernet hardware address from
+	   the EEPROM */
+	station_addr[0] = read_eeprom(ioaddr, 2, dev);
+
+	/* FIXME - find another way to know that we've found
+	 * an Etherexpress 10
+	 */
+	if (station_addr[0] == 0x0000 ||
+	    station_addr[0] == 0xffff) {
+		lp->eepro = LAN595FX_10ISA;
 		lp->eeprom_reg = EEPROM_REG_10;
 		lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
 		lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
 		lp->xmt_bar = XMT_BAR_10;
 				station_addr[0] = read_eeprom(ioaddr, 2, dev);
-			}
-			station_addr[1] = read_eeprom(ioaddr, 3, dev);
-			station_addr[2] = read_eeprom(ioaddr, 4, dev);
+	}
+	station_addr[1] = read_eeprom(ioaddr, 3, dev);
+	station_addr[2] = read_eeprom(ioaddr, 4, dev);
 
 	if (!lp->eepro) {
 		if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ)
 			lp->eepro = 2;
 		else if (station_addr[2] == SA_ADDR1)
 			lp->eepro = 1;
-			}
+	}
 
-			/* Fill in the 'dev' fields. */
-			dev->base_addr = ioaddr;
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
 
 	for (i=0; i < 6; i++)
-				dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+		dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
 
 	/* RX buffer must be more than 3K and less than 29K */
 	if (dev->mem_end < 3072 || dev->mem_end > 29696)
@@ -800,59 +800,58 @@
 	/* calculate {xmt,rcv}_{lower,upper}_limit */
 	eepro_recalc(dev);
 
-
-			if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
-				dev->if_port = BNC;
+	if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
+		dev->if_port = BNC;
 	else
 		dev->if_port = TPE;
 
 	if ((dev->irq < 2) && (lp->eepro!=0)) {
-				i = read_eeprom(ioaddr, 1, dev);
-				irqMask = read_eeprom(ioaddr, 7, dev);
-				i &= 0x07; /* Mask off INT number */
-
-				for (j=0; ((j<16) && (i>=0)); j++) {
-					if ((irqMask & (1<<j))!=0) {
-						if (i==0) {
-							dev->irq = j;
-							break; /* found bit corresponding to irq */
-						}
-						i--; /* count bits set in irqMask */
-					}
+		i = read_eeprom(ioaddr, 1, dev);
+		irqMask = read_eeprom(ioaddr, 7, dev);
+		i &= 0x07; /* Mask off INT number */
+
+		for (j=0; ((j<16) && (i>=0)); j++) {
+			if ((irqMask & (1<<j))!=0) {
+				if (i==0) {
+					dev->irq = j;
+					break; /* found bit corresponding to irq */
 				}
-				if (dev->irq < 2) {
+				i--; /* count bits set in irqMask */
+			}
+		}
+		if (dev->irq < 2) {
 			printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
-					kfree(dev->priv);
+			kfree(dev->priv);
 			retval = -ENODEV;
 			goto freeall;
-				} else
-			if (dev->irq==2) dev->irq = 9;
-			}
+		} 
+		else if (dev->irq==2) dev->irq = 9;
+	}
 
-			/* Grab the region so we can find another board if autoIRQ fails. */
-			if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { 
-				printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr);
-				goto freeall;
-			}
-			((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED;
+	/* Grab the region so we can find another board if autoIRQ fails. */
+	if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { 
+		printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr);
+		goto freeall;
+	}
+	((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED;
 
-			dev->open               = eepro_open;
-			dev->stop               = eepro_close;
-			dev->hard_start_xmit    = eepro_send_packet;
-			dev->get_stats          = eepro_get_stats;
-			dev->set_multicast_list = &set_multicast_list;
-			dev->tx_timeout		= eepro_tx_timeout;
-			dev->watchdog_timeo	= TX_TIMEOUT;
-
-			/* Fill in the fields of the device structure with
-			   ethernet generic values */
-			ether_setup(dev);
+	dev->open               = eepro_open;
+	dev->stop               = eepro_close;
+	dev->hard_start_xmit    = eepro_send_packet;
+	dev->get_stats          = eepro_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->tx_timeout		= eepro_tx_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+
+	/* Fill in the fields of the device structure with
+	ethernet generic values */
+	ether_setup(dev);
 
 	/* print boot time info */
 	eepro_print_info(dev);
 
 	/* reset 82595 */
-			eepro_reset(ioaddr);
+	eepro_reset(ioaddr);
 
 exit:
 	return retval;
diff -urN linux-2.4.20-pre2/drivers/net/irda/irda-usb.c linux-2.4.20-pre3/drivers/net/irda/irda-usb.c
--- linux-2.4.20-pre2/drivers/net/irda/irda-usb.c	Sat Aug 17 14:18:19 2002
+++ linux-2.4.20-pre3/drivers/net/irda/irda-usb.c	Sat Aug 17 14:18:51 2002
@@ -45,6 +45,8 @@
  * Amongst the reasons :
  *	o uhci doesn't implement USB_ZERO_PACKET
  *	o uhci non-compliant use of urb->timeout
+ * The final fix for USB_ZERO_PACKET in uhci is likely to be in 2.4.19 and
+ * 2.5.8. With this fix, the driver will work properly. More on that later.
  *
  * Jean II
  */
@@ -243,12 +245,12 @@
 /*------------------------------------------------------------------*/
 /*
  * Send a command to change the speed of the dongle
+ * Need to be called with spinlock on.
  */
 static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 {
-	unsigned long flags;
 	__u8 *frame;
-	struct urb *urb;
+	struct urb *purb;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
@@ -261,8 +263,6 @@
 		return;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Allocate the fake frame */
 	frame = self->speed_buff;
 
@@ -281,7 +281,6 @@
 	if ((ret = usb_submit_urb(purb))) {
 		WARNING(__FUNCTION__ "(), failed Speed URB\n");
 	}
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*------------------------------------------------------------------*/
@@ -335,14 +334,20 @@
 	s16 xbofs;
 	int res, mtt;
 
-	/* Check if the device is still there */
+	netif_stop_queue(netdev);
+
+	/* Protect us from USB callbacks, net watchdog and else. */
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Check if the device is still there.
+	 * We need to check self->present under the spinlock because
+	 * of irda_usb_disconnect() is synchronous - Jean II */
 	if ((!self) || (!self->present)) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+		spin_unlock_irqrestore(&self->lock, flags);
 		return 1;	/* Failed */
 	}
 
-	netif_stop_queue(netdev);
-
 	/* Check if we need to change the number of xbofs */
         xbofs = irda_get_next_xbofs(skb);
         if ((xbofs != self->xbofs) && (xbofs != -1)) {
@@ -366,16 +371,14 @@
 			 * Jean II */
 			irda_usb_change_speed_xbofs(self);
 			netdev->trans_start = jiffies;
-			dev_kfree_skb(skb);
 			/* Will netif_wake_queue() in callback */
-			return 0;
+			goto drop;
 		}
 	}
 
 	if (purb->status != USB_ST_NOERROR) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
-		dev_kfree_skb(skb);
-		return 0;
+		goto drop;
 	}
 
 	/* Make sure there is room for IrDA-USB header. The actual
@@ -386,13 +389,10 @@
 		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");
 		if (skb_cow(skb, USB_IRDA_HEADER)) {
 			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");
-			dev_kfree_skb(skb);
-			return 0;
+			goto drop;
 		}
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Change setting for next frame */
 	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
 
@@ -473,6 +473,12 @@
 	spin_unlock_irqrestore(&self->lock, flags);
 	
 	return 0;
+
+drop:
+	/* Drop silently the skb and exit */
+	dev_kfree_skb(skb);
+	spin_unlock_irqrestore(&self->lock, flags);
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -481,6 +487,7 @@
  */
 static void write_bulk_callback(struct urb *purb)
 {
+	unsigned long flags;
 	struct sk_buff *skb = purb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
 	
@@ -511,11 +518,15 @@
 	}
 
 	/* urb is now available */
-	purb->status = USB_ST_NOERROR;
+	//purb->status = USB_ST_NOERROR; -> tested above
+
+	/* Make sure we read self->present properly */
+	spin_lock_irqsave(&self->lock, flags);
 
 	/* If the network is closed, stop everything */
 	if ((!self->netopen) || (!self->present)) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
+		spin_unlock_irqrestore(&self->lock, flags);
 		return;
 	}
 
@@ -527,6 +538,7 @@
 		/* Otherwise, allow the stack to send more packets */
 		netif_wake_queue(self->netdev);
 	}
+	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*------------------------------------------------------------------*/
@@ -540,15 +552,20 @@
  */
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
+	unsigned long flags;
 	struct irda_usb_cb *self = netdev->priv;
 	struct urb *purb;
 	int	done = 0;	/* If we have made any progress */
 
 	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
 
+	/* Protect us from USB callbacks, net Tx and else. */
+	spin_lock_irqsave(&self->lock, flags);
+
 	if ((!self) || (!self->present)) {
 		WARNING(__FUNCTION__ "(), device not present!\n");
 		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&self->lock, flags);
 		return;
 	}
 
@@ -623,6 +640,7 @@
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	/* Maybe we need a reset */
 	/* Note : Some drivers seem to use a usb_set_interface() when they
@@ -1013,8 +1031,10 @@
 			purb->context = NULL;
 		}
 	}
-	/* Cancel Tx and speed URB */
+	/* Cancel Tx and speed URB - need to be synchronous to avoid races */
+	self->tx_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 	usb_unlink_urb(&(self->tx_urb));
+	self->speed_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 	usb_unlink_urb(&(self->speed_urb));
 
 	/* Stop and remove instance of IrLAP */
@@ -1033,6 +1053,7 @@
  */
 static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	unsigned long flags;
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
 	struct irda_usb_cb *self;
 	int ret = 0;
@@ -1043,23 +1064,26 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 
-	/* Check if the device is still there */
-	if(!self->present)
-		return -EFAULT;
-
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		/* Set the desired speed */
-		self->new_speed = irq->ifr_baudrate;
-		irda_usb_change_speed_xbofs(self);
-		/* Note : will spinlock in above function */
+		/* Protect us from USB callbacks, net watchdog and else. */
+		spin_lock_irqsave(&self->lock, flags);
+		/* Check if the device is still there */
+		if(self->present) {
+			/* Set the desired speed */
+			self->new_speed = irq->ifr_baudrate;
+			irda_usb_change_speed_xbofs(self);
+		}
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		irda_device_set_media_busy(self->netdev, TRUE);
+		/* Check if the IrDA stack is still there */
+		if(self->netopen)
+			irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		irq->ifr_receiving = irda_usb_is_receiving(self);
@@ -1409,8 +1433,7 @@
 		dev->descriptor.idProduct);
 
 	/* Try to cleanup all instance that have a pending disconnect
-	 * Instance will be in this state is the disconnect() occurs
-	 * before the net_close().
+	 * In theory, it can't happen any longer.
 	 * Jean II */
 	for (i = 0; i < NIRUSB; i++) {
 		struct irda_usb_cb *irda = &irda_instance[i];
@@ -1494,33 +1517,47 @@
 /*
  * The current irda-usb device is removed, the USB layer tell us
  * to shut it down...
+ * One of the constraints is that when we exit this function,
+ * we cannot use the usb_device no more. Gone. Destroyed. kfree().
+ * Most other subsystem allow you to destroy the instance at a time
+ * when it's convenient to you, to postpone it to a later date, but
+ * not the USB subsystem.
+ * So, we must make bloody sure that everything gets deactivated.
+ * Jean II
  */
 static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
 {
+	unsigned long flags;
 	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
 	int i;
 
 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
-	/* Oups ! We are not there any more */
+	/* Make sure that the Tx path is not executing. - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Oups ! We are not there any more.
+	 * This will stop/desactivate the Tx path. - Jean II */
 	self->present = 0;
 
-	/* Hum... Check if networking is still active */
-	if (self->netopen) {
+	/* We need to have irq enabled to unlink the URBs. That's OK,
+	 * at this point the Tx path is gone - Jean II */
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	/* Hum... Check if networking is still active (avoid races) */
+	if((self->netopen) || (self->irlap)) {
 		/* Accept no more transmissions */
 		/*netif_device_detach(self->netdev);*/
 		netif_stop_queue(self->netdev);
 		/* Stop all the receive URBs */
 		for (i = 0; i < IU_MAX_RX_URBS; i++)
 			usb_unlink_urb(&(self->rx_urb[i]));
-		/* Cancel Tx and speed URB */
+		/* Cancel Tx and speed URB.
+		 * Toggle flags to make sure it's synchronous. */
+		self->tx_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 		usb_unlink_urb(&(self->tx_urb));
+		self->speed_urb.transfer_flags &= ~USB_ASYNC_UNLINK;
 		usb_unlink_urb(&(self->speed_urb));
-
-		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
-		/* better not do anything just yet, usb_irda_cleanup()
-		 * will do whats needed */
-		return;
 	}
 
 	/* Cleanup the device stuff */
@@ -1570,7 +1607,8 @@
 	struct irda_usb_cb *irda = NULL;
 	int	i;
 
-	/* Find zombie instances and kill them... */
+	/* Find zombie instances and kill them...
+	 * In theory, it can't happen any longer. Jean II */
 	for (i = 0; i < NIRUSB; i++) {
 		irda = &irda_instance[i];
 		/* If the Device is zombie */
diff -urN linux-2.4.20-pre2/drivers/net/slip.c linux-2.4.20-pre3/drivers/net/slip.c
--- linux-2.4.20-pre2/drivers/net/slip.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre3/drivers/net/slip.c	Sat Aug 17 14:18:51 2002
@@ -1393,10 +1393,8 @@
 		/* First of all: check for active disciplines and hangup them.
 		 */
 		do {
-			if (busy) {
-				current->counter = 0;
-				schedule();
-			}
+			if (busy)
+				yield();
 
 			busy = 0;
 			local_bh_disable();
diff -urN linux-2.4.20-pre2/drivers/pci/pci.c linux-2.4.20-pre3/drivers/pci/pci.c
--- linux-2.4.20-pre2/drivers/pci/pci.c	Sat Aug 17 14:18:20 2002
+++ linux-2.4.20-pre3/drivers/pci/pci.c	Sat Aug 17 14:18:52 2002
@@ -358,25 +358,41 @@
 }
 
 /**
- * pci_enable_device - Initialize device before it's used by a driver.
+ * pci_enable_device_bars - Initialize some of a device for use
  * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
  *
  *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ *  to enable selected I/O and memory resources. Wake up the device if it 
+ *  was suspended. Beware, this function can fail.
  */
+ 
 int
-pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
 {
 	int err;
 
 	pci_set_power_state(dev, 0);
-	if ((err = pcibios_enable_device(dev)) < 0)
+	if ((err = pcibios_enable_device(dev, bars)) < 0)
 		return err;
 	return 0;
 }
 
 /**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	return pci_enable_device_bars(dev, 0x3F);
+}
+
+/**
  * pci_disable_device - Disable PCI device after use
  * @dev: PCI device to be disabled
  *
@@ -2066,6 +2082,7 @@
 EXPORT_SYMBOL(pci_write_config_dword);
 EXPORT_SYMBOL(pci_devices);
 EXPORT_SYMBOL(pci_root_buses);
+EXPORT_SYMBOL(pci_enable_device_bars);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_disable_device);
 EXPORT_SYMBOL(pci_find_capability);
diff -urN linux-2.4.20-pre2/drivers/pci/pci.ids linux-2.4.20-pre3/drivers/pci/pci.ids
--- linux-2.4.20-pre2/drivers/pci/pci.ids	Sat Aug 17 14:18:20 2002
+++ linux-2.4.20-pre3/drivers/pci/pci.ids	Sat Aug 17 14:18:52 2002
@@ -7,7 +7,7 @@
 #	so if you have anything to contribute, please visit the home page or
 #	send a diff -u against the most recent pci.ids to pci-ids@ucw.cz.
 #
-#	$Id: pci.ids,v 1.39 2002/03/23 14:58:55 mares Exp $
+#	$Id: pci.ids,v 1.46 2002/08/14 17:38:51 mares Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -73,12 +73,31 @@
 	ae6d  NorthStar CPU to PCI Bridge
 	b011  Integrated Netelligent 10/100
 	b012  Netelligent 10 T/2
+	b01e  NC3120 Fast Ethernet NIC
+	b01f  NC3122 Fast Ethernet NIC
 	b02f  NC1120 Ethernet NIC
 	b030  Netelligent WS 5100
+	b04a  10/100 TX PCI Intel WOL UTP Controller
 	b060  Smart Array 5300 Controller
+	b0c6  NC3161 Fast Ethernet NIC
+	b0c7  NC3160 Fast Ethernet NIC
+	b0d7  NC3121 Fast Ethernet NIC
+	b0dd  NC3131 Fast Ethernet NIC
+	b0de  NC3132 Fast Ethernet Module
+	b0df  NC6132 Gigabit Module
+	b0e0  NC6133 Gigabit Module
+	b0e1  NC3133 Fast Ethernet Module
+	b123  NC6134 Gigabit NIC
+	b134  NC3163 Fast Ethernet NIC
+	b13c  NC3162 Fast Ethernet NIC
+	b144  NC3123 Fast Ethernet NIC
+	b163  NC3134 Fast Ethernet NIC
+	b164  NC3165 Fast Ethernet Upgrade Module
 	b178  Smart Array 5i/532
+	b1a4  NC7131 Gigabit Server Adapter
 	f130  NetFlex-3/P ThunderLAN 1.0
 	f150  NetFlex-3/P ThunderLAN 2.3
+0e55  HaSoTec GmbH
 1000  LSI Logic / Symbios Logic (formerly NCR)
 	0001  53c810
 		1000 1000  8100S
@@ -90,6 +109,7 @@
 	000a  53c1510
 	000b  53c896
 	000c  53c895
+		1de1 3907  DC-390U2W
 	000d  53c885
 	000f  53c875
 		0e11 7004  Embedded Ultra Wide SCSI Controller
@@ -99,9 +119,12 @@
 		0e11 4040  Integrated Array Controller
 		0e11 4048  Integrated Array Controller
 	0012  53c895a
+	0013  53c875a
 	0020  53c1010 Ultra3 SCSI Adapter
+		1de1 1020  DC-390U3W
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
 	0030  53c1030
+		1028 1010  LSI U320 SCSI Controller
 	0040  53c1035
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
@@ -120,7 +143,11 @@
 		1318 0000  PEI100X
 	0901  61C102
 	1000  63C815
-1001  Initio
+	1960  PowerEdge Expandable RAID Controller 4
+		1028 0518  PowerEdge Expandable RAID Controller 4/DC
+		1028 0520  PowerEdge Expandable RAID Controller 4/SC
+		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+1001  Kolter Electronic
 	0010  PCI 1616 Measurement card with 32 digital I/O lines
 	0011  OPTO-PCI Opto-Isolated digital I/O board
 	0012  PCI-AD/DA Analogue I/O board
@@ -228,9 +255,11 @@
 	4c54  264LT [Mach64 LT]
 	4c57  Radeon Mobility M7 LW
 		1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)
-	4c58  Radeon Mobility M6 LX
+	4c58  Radeon Mobility M7 LX [Radeon Mobility FireGL 7800]
 	4c59  Radeon Mobility M6 LY
-		104d 80e7  Vaio PCG Series video card
+		1014 0235  ThinkPad A30p (2653-64G)
+		1014 0239  ThinkPad X22/X23/X24
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	4c5a  Radeon Mobility M6 LZ
 	4d46  Rage Mobility M4 AGP
 	4d4c  Rage Mobility M4 AGP
@@ -287,14 +316,18 @@
 	5145  Radeon QE
 	5146  Radeon QF
 	5147  Radeon QG
-	5148  Radeon R200 QH
+	5148  Radeon R200 QH [Radeon 8500]
+		1002 0152  FireGL 8800
+		1002 0172  FireGL 8700
 	5149  Radeon R200 QI
 	514a  Radeon R200 QJ
 	514b  Radeon R200 QK
-	514c  Radeon QL
+	514c  Radeon R200 QL [Radeon 8500 LE]
+		1002 003a  Radeon R200 QL [Radeon 8500 LE]
 		1002 013a  Radeon 8500
 	5157  Radeon 7500 QW
 		1002 013a  Radeon 7500
+		174b 7161  Radeon RV200 QW [Radeon 7500 LE]
 	5158  Radeon 7500 QX
 	5159  Radeon VE QY
 		1002 000a  Radeon 7000/Radeon VE
@@ -302,6 +335,7 @@
 		1002 003a  Radeon 7000/Radeon VE
 		1002 00ba  Radeon 7000/Radeon VE
 		1002 013a  Radeon 7000/Radeon VE
+		174b 7112  Radeon 7000 64M TVO
 	515a  Radeon VE QZ
 	5168  Radeon R200 Qh
 	5169  Radeon R200 Qi
@@ -435,6 +469,7 @@
 	0007  NVRAM [Zephyr NVRAM]
 	0008  KZPSA [KZPSA]
 	0009  DECchip 21140 [FasterNet]
+		1025 0310  21140 Fast Ethernet
 		10b8 2001  SMC9332BDT EtherPower 10/100
 		10b8 2002  SMC9332BVT EtherPower T4 10/100
 		10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)
@@ -447,6 +482,7 @@
 		1186 1112  DFE-570TX Fast Ethernet
 		1186 1140  DFE-660 Cardbus Ethernet 10/100
 		1186 1142  DFE-660 Cardbus Ethernet 10/100
+		11f6 0503  Freedomline Fast Ethernet
 		1282 9100  AEF-380TXD Fast Ethernet
 		1385 1100  FA310TX Fast Ethernet
 		2646 0001  KNE100TX Fast Ethernet
@@ -457,11 +493,16 @@
 		1186 0100  DE-530+
 	0016  DGLPB [OPPO]
 	0019  DECchip 21142/43
-		1011 500b  DE500 Fast Ethernet
+		1011 500a  DE500A Fast Ethernet
+		1011 500b  DE500B Fast Ethernet
 		1014 0001  10/100 EtherJet Cardbus
 		1025 0315  ALN315 Fast Ethernet
+		1033 800c  PC-9821-CS01
+		1033 800d  PC-9821NR-B06
 		108d 0016  Rapidfire 2327 10/100 Ethernet
+		108d 0017  GoCard 2250 Ethernet 10/100 Cardbus
 		10b8 2005  SMC8032DT Extreme Ethernet 10/100
+		10b8 8034  SMC8034 Extreme Ethernet 10/100
 		10ef 8169  Cardbus Fast Ethernet
 		1109 2a00  ANA-6911A/TX Fast Ethernet
 		1109 2b00  ANA-6911A/TXC Fast Ethernet
@@ -474,10 +515,15 @@
 		1186 1100  DFE-500TX Fast Ethernet
 		1186 1101  DFE-500TX Fast Ethernet
 		1186 1102  DFE-500TX Fast Ethernet
+		1259 2800  AT-2800Tx Fast Ethernet
 		1266 0004  Eagle Fast EtherMAX
 		12af 0019  NetFlyer Cardbus Fast Ethernet
 		1374 0001  Cardbus Ethernet Card 10/100
+		1374 0002  Cardbus Ethernet Card 10/100
+		1374 0007  Cardbus Ethernet Card 10/100
+		1374 0008  Cardbus Ethernet Card 10/100
 		1395 0001  10/100 Ethernet CardBus PC Card
+		13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
 	001a  Farallon PN9000SX
 	0021  DECchip 21052
@@ -486,6 +532,8 @@
 	0024  DECchip 21152
 	0025  DECchip 21153
 	0026  DECchip 21154
+	0034  56k Modem Cardbus
+		1374 0003  56k Modem Cardbus
 	0045  DECchip 21553
 	0046  DECchip 21554
 		0e11 4050  Integrated Smart Array
@@ -496,8 +544,9 @@
 		9005 0365  Adaptec 5400S
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
+		e4bf 1000  CC8-1-BLUES
 	1065  StrongARM DC21285
-		1069 0020  DAC960P
+		1069 0020  DAC960P / DAC1164P
 1012  Micronics Computers Inc
 1013  Cirrus Logic
 	0038  GD 7548
@@ -515,7 +564,10 @@
 	00d0  GD 5462
 	00d2  GD 5462 [Laguna I]
 	00d4  GD 5464 [Laguna]
+	00d5  GD 5464 BD [Laguna]
 	00d6  GD 5465 [Laguna]
+		13ce 8031  Barco Metheus 2 Megapixel, Dual Head
+		13cf 8031  Barco Metheus 2 Megapixel, Dual Head
 	00e8  GD 5436U
 	1100  CL 6729
 	1110  PD 6832 PCMCIA/CardBus Ctrlr
@@ -591,6 +643,8 @@
 	00b7  256-bit Graphics Rasterizer [Fire GL1]
 		1902 00b8  Fire GL1
 	00be  ATM 622MBPS Controller (1410be00)
+	00fc  CPC710 Dual Bridge and Memory Controller (PCI-64)
+	0105  CPC710 Dual Bridge and Memory Controller (PCI-32)
 	0142  Yotta Video Compositor Input
 		1014 0143  Yotta Input Controller (ytin)
 	0144  Yotta Video Compositor Output
@@ -629,7 +683,9 @@
 		101e 0475  MegaRAID 475 Express 500 RAID Controller
 		101e 0493  MegaRAID 493 Elite 1600 RAID Controller
 		1028 0471  PowerEdge RAID Controller 3/QC
+		1028 0475  PowerEdge RAID Controller 3/SC
 		1028 0493  PowerEdge RAID Controller 3/DC
+		1028 0511  PowerEdge Cost Effective RAID Controller ATA100/4Ch
 	9010  MegaRAID 428 Ultra RAID Controller
 	9030  EIDE Controller
 	9031  EIDE Controller
@@ -638,6 +694,7 @@
 	9040  Multimedia card
 	9060  MegaRAID 434 Ultra GT RAID Controller
 	9063  MegaRAC
+		101e 0767  Dell Remote Assistant Card 2
 101f  PictureTel
 1020  Hitachi Computer Products
 1021  OKI Electric Industry Co. Ltd.
@@ -660,6 +717,7 @@
 		1668 0299  ActionLink Home Network Adapter
 	2020  53c974 [PCscsi]
 	2040  79c974
+	3000  ELanSC520 Microcontroller
 	7006  AMD-751 [Irongate] System Controller
 	7007  AMD-751 [Irongate] AGP Bridge
 	700c  AMD-760 MP [IGD4-2P] System Controller
@@ -679,10 +737,11 @@
 	7413  AMD-766 [ViperPlus] ACPI
 	7414  AMD-766 [ViperPlus] USB
 	7440  AMD-768 [Opus] ISA
-		1043 8044  Asus A7M-D motherboard ISA bridge
+		1043 8044  A7M-D Mainboard
 	7441  AMD-768 [Opus] IDE
 	7443  AMD-768 [Opus] ACPI
-		1043 8044  Asus A7M-D motherboard
+		1043 8044  A7M-D Mainboard
+	7445  AMD-768 [Opus] Audio
 	7448  AMD-768 [Opus] PCI
 	7449  AMD-768 [Opus] USB
 	7454  AMD-8151 System Controller
@@ -726,8 +785,9 @@
 	9470  TGUI 9470
 	9520  Cyber 9520
 	9525  Cyber 9525
+		10cf 1094  Lifebook C6155
 	9540  Cyber 9540
-	9660  TGUI 9660/968x/968x
+	9660  TGUI 9660/938x/968x
 	9680  TGUI 9680
 	9682  TGUI 9682
 	9683  TGUI 9683
@@ -804,15 +864,26 @@
 		10b9 7101  M7101 PCI PMU Power Management Controller
 1028  Dell Computer Corporation
 	0001  PowerEdge Expandable RAID Controller 2/Si
-	0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 0001  PowerEdge Expandable RAID Controller 2/Si
+	0002  PowerEdge Expandable RAID Controller 3
+		1028 0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d1  PowerEdge Expandable RAID Controller 3/Di
+		1028 00d9  PowerEdge Expandable RAID Controller 3/Di
 	0003  PowerEdge Expandable RAID Controller 3/Si
+		1028 0003  PowerEdge Expandable RAID Controller 3/Si
 	0004  PowerEdge Expandable RAID Controller 3/Si
+		1028 00d0  PowerEdge Expandable RAID Controller 3/Si
 	0005  PowerEdge Expandable RAID Controller 3/Di
 	0006  PowerEdge Expandable RAID Controller 3/Di
-	0007  Remote Assitant Card 3
+	0007  Remote Assistant Card 3
 	0008  PowerEdge Expandable RAID Controller 3/Di
-	000a  PowerEdge Expandable RAID Controller 3/Di
+	000a  PowerEdge Expandable RAID Controller 3
+		1027 0121  PowerEdge Expandable RAID Controller 3/Di
+		1028 0106  PowerEdge Expandable RAID Controller 3/Di
+		1028 011b  PowerEdge Expandable RAID Controller 3/Di
 	000c  Embedded Systems Management Device 4
+	000e  PowerEdge Expandable RAID Controller
+	000f  PowerEdge Expandable RAID Controller 4/Di
 1029  Siemens Nixdorf IS
 102a  LSI Logic
 	0000  HYDRA
@@ -922,6 +993,8 @@
 		1705 0003  Digital First Millennium G450 32MB
 		1705 0004  Digital First Millennium G450 16MB
 		b16f 0e11  MGA-G400 AGP
+	0527  MGA Parhelia AGP
+		102b 0840  Parhelia 128Mb
 	0d10  MGA Ultima/Impression
 	1000  MGA G100 [Productiva]
 		102b ff01  Productiva G100
@@ -955,12 +1028,14 @@
 	00f0  F68554
 	00f4  F68554 HiQVision
 	00f5  F68555
+	0c30  F69030
 102d  Wyse Technology Inc.
 	50dc  3328 Audio
 102e  Olivetti Advanced Technology
 102f  Toshiba America
 	0009  r4x00
 	0020  ATM Meteor 155
+		102f 00f8  ATM Meteor 155
 1030  TMC Research
 1031  Miro Computer Products AG
 	5601  DC20 ASIC
@@ -983,6 +1058,7 @@
 	0029  PowerVR PCX1
 	002a  PowerVR 3D
 	0035  USB
+		1179 0001  USB
 		12ee 7000  Root Hub
 	003e  NAPCCARD Cardbus Controller
 	0046  PowerVR PCX2 [midas]
@@ -1018,10 +1094,12 @@
 	0008  85C503/5513
 	0009  ACPI
 	0018  SiS85C503/5513 (LPC Bridge)
-	0200  5597/5598 VGA
+	0200  5597/5598/6326 VGA
 		1039 0000  SiS5597 SVGA (Shared RAM)
 	0204  82C204
 	0205  SG86C205
+	0300  300/200
+		107d 2720  Leadtek WinFast VR300
 	0406  85C501/2
 	0496  85C496
 	0530  530 Host
@@ -1030,10 +1108,19 @@
 	0601  85C601
 	0620  620 Host
 	0630  630 Host
+	0633  633 Host
+	0635  635 Host
+	0645  645 Host
+	0646  645DX Host
+	0650  650 Host
 	0730  730 Host
+	0733  733 Host
 	0735  735 Host
+	0740  740 Host
+	0745  745 Host
 	0900  SiS900 10/100 Ethernet
 		1039 0900  SiS900 10/100 Ethernet Adapter
+	0961  SiS961 [MuTIOL Media IO]
 	3602  83C602
 	5107  5107
 	5300  SiS540 PCI Display Adapter
@@ -1055,7 +1142,7 @@
 	6300  SiS630 GUI Accelerator+3D
 	6306  6306 3D-AGP
 		1039 6306  SiS530,620 GUI Accelerator+3D
-	6326  86C326
+	6326  86C326 5598/6326
 		1039 6326  SiS6326 GUI Accelerator
 		1092 0a50  SpeedStar A50
 		1092 0a70  SpeedStar A70
@@ -1095,6 +1182,9 @@
 103b  Tatung Co. of America
 103c  Hewlett-Packard Company
 	1005  A4977A Visualize EG
+	1006  Visualize FX6
+	1008  Visualize FX4
+	100a  Visualize FX2
 	1028  Tach TL Fibre Channel Host Adapter
 	1029  Tach XL2 Fibre Channel Host Adapter
 		107e 000f  Interphase 5560 Fibre Channel Adapter
@@ -1112,7 +1202,16 @@
 	1040  J2973A DeskDirect 10BaseT NIC
 	1041  J2585B DeskDirect 10/100 NIC
 	1042  J2970A DeskDirect 10BaseT/2 NIC
+	1048  Diva Serial [GSP] Multiport UART
+		103c 1049  Tosca Console
+		103c 104a  Tosca Secondary
+		103c 104b  Maestro SP2
+		103c 1223  Halfdome Console
+		103c 1226  Keystone SP2
+		103c 1227  Powerbar SP2
+		103c 1282  Everest SP2
 	1064  79C970 PCnet Ethernet Controller
+	108b  Visualize FXe
 	10c1  NetServer Smart IRQ Router
 	10ed  TopTools Remote Control
 	1200  82557B 10/100 NIC
@@ -1123,6 +1222,7 @@
 	1229  zx1 System Bus Adapter
 	122a  zx1 I/O Controller
 	122e  zx1 Local Bus Adapter
+	1290  Auxiliary Diva Serial Port
 	2910  E2910A PCIBus Exerciser
 	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
@@ -1189,8 +1289,8 @@
 	c567  82C750 [Vendetta], device 0
 	c568  82C750 [Vendetta], device 1
 	c569  82C579 [Viper XPress+ Chipset]
-	c621  82C621
-	c700  82C700
+	c621  82C621 [Viper-M/N+]
+	c700  82C700 [FireStar]
 	c701  82C701 [FireStar Plus]
 	c814  82C814 [Firebridge 1]
 	c822  82C822
@@ -1201,9 +1301,11 @@
 	c895  82C895
 	c935  EV1935 ECTIVA MachOne PCI Audio
 	d568  82C825 [Firebridge 2]
+	d721  IDE [FireStar]
 1046  IPC Corporation, Ltd.
 1047  Genoa Systems Corp
 1048  Elsa AG
+	0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]
 	1000  QuickStep 1000
 	3000  QuickStep 3000
 1049  Fountain Technologies, Inc.
@@ -1257,14 +1359,17 @@
 		e4bf 1010  CF2-1-CYMBAL
 	8020  TSB12LV26 IEEE-1394 Controller (Link)
 	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
-		104d 80e7  Notebook Computer Vaio PCG Series
-	8022  TSB43AB22 IEEE-1394 Controller (PHY/Link) 1394a-2000
-	8024  TSB43AB23 IEEE-1394 Controller (PHY/Link) 1394a-2000
-	8026  TSB43AB21 IEEE-1394 Controller (PHY/Link) 1394a-2000
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	8022  TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link)
+	8023  TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link)
+	8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
+	8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)
 	8027  PCI4451 IEEE-1394 Controller
 		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
 	a001  TDC1570
 	a100  TDC1561
+	a102  TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f
 	ac10  PCI1050
 	ac11  PCI1053
 	ac12  PCI1130
@@ -1282,6 +1387,9 @@
 	ac1f  PCI1251B
 	ac20  TI 2030
 	ac21  PCI2031
+	ac22  PCI2032 PCI Docking Bridge
+	ac23  PCI2250 PCI-to-PCI Bridge
+	ac28  PCI2050 PCI-to-PCI Bridge
 	ac30  PCI1260 PC card Cardbus Controller
 	ac40  PCI4450 PC card Cardbus Controller
 	ac41  PCI4410 PC card Cardbus Controller
@@ -1289,8 +1397,13 @@
 		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
 	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
+		1014 023b  ThinkPad T23 (2647-4MG)
+		10cf 1095  Lifebook C6155
+		e4bf 1000  CP2-2-HIPHOP
 	ac52  PCI1451 PC card Cardbus Controller
 	ac53  PCI1421 PC card Cardbus Controller
+	ac55  PCI1250 PC card Cardbus Controller
+	ac60  PCI2040 PCI to DSP Bridge Controller
 	fe00  FireWire Host Controller
 	fe03  12C01A FireWire Host Controller
 104d  Sony Corporation
@@ -1298,7 +1411,6 @@
 	8039  CXD3222 i.LINK Controller
 	8056  Rockwell HCF 56K modem
 	808a  Memory Stick Controller
-	80e7  Vaio PCG-GR114MK
 104e  Oak Technology, Inc
 	0017  OTI-64017
 	0107  OTI-107 [Spitfire]
@@ -1321,20 +1433,22 @@
 1052  ?Young Micro Systems
 1053  Young Micro Systems
 1054  Hitachi, Ltd
-1055  EFAR Microsystems
-	9130  EIDE Controller
-	9460  PCI to ISA Bridge
-	9462  USB Universal Host Controller
-	9463  Power Management Controller [Bridge]
+1055  Efar Microsystems
+	9130  SLC90E66 [Victory66] IDE
+	9460  SLC90E66 [Victory66] ISA
+	9462  SLC90E66 [Victory66] USB
+	9463  SLC90E66 [Victory66] ACPI
 1056  ICL
 # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.
 1057  Motorola
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
 	0100  MC145575 [HFC-PCI]
 	0431  KTI829c 100VG
 	1801  Audio I/O Controller (MIDI)
 		ecc0 0030  Layla
+	18c0  MPC8265A/MPC8266
 	4801  Raven
 	4802  Falcon
 	4803  Hawk
@@ -1358,6 +1472,7 @@
 		14c8 0302  SM56 PCI Fax Modem
 		1668 0300  SM56 PCI Speakerphone Modem
 		1668 0302  SM56 PCI Fax Modem
+	6400  MPC190 Security Processor (S1 family, encryption)
 1058  Electronics & Telecommunications RSH
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
@@ -1365,10 +1480,12 @@
 		105a 4d33  Ultra100
 	0d38  20263
 		105a 4d39  Fasttrak66
+	1275  20275
 	4d30  20267
 		105a 4d33  Ultra100
 		105a 4d39  Fasttrak100
 	4d33  20246
+		105a 4d33  20246 IDE Controller
 	4d38  20262
 		105a 4d30  Ultra Device on SuperTrak
 		105a 4d33  Ultra66
@@ -1380,6 +1497,9 @@
 		105a 0275  SuperTrak SX6000 IDE
 	5300  DC5300
 	6268  20268R
+	6269  PDC20271
+		105a 6269  Fasttrack tx2
+	7275  PDC20277
 105b  Foxconn International, Inc.
 105c  Wipro Infotech Limited
 105d  Number 9 Computer Company
@@ -1397,7 +1517,24 @@
 		105d 0009  Imagine 128 series 2e 4Mb DRAM
 		105d 000a  Imagine 128 series 2 8Mb VRAM
 		105d 000b  Imagine 128 series 2 8Mb H-VRAM
+		11a4 000a  Barco Metheus 5 Megapixel
+		13cc 0000  Barco Metheus 5 Megapixel
+		13cc 0004  Barco Metheus 5 Megapixel
+		13cc 0005  Barco Metheus 5 Megapixel
+		13cc 0006  Barco Metheus 5 Megapixel
+		13cc 0008  Barco Metheus 5 Megapixel
+		13cc 0009  Barco Metheus 5 Megapixel
+		13cc 000a  Barco Metheus 5 Megapixel
+		13cc 000c  Barco Metheus 5 Megapixel
 	493d  Imagine 128 T2R [Ticket to Ride]
+		11a4 000a  Barco Metheus 5 Megapixel, Dual Head
+		11a4 000b  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0002  Barco Metheus 4 Megapixel, Dual Head
+		13cc 0003  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0007  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0008  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0009  Barco Metheus 5 Megapixel, Dual Head
+		13cc 000a  Barco Metheus 5 Megapixel, Dual Head
 	5348  Revolution 4
 105e  Vtech Computers Ltd
 105f  Infotronic America Inc
@@ -1433,10 +1570,12 @@
 1065  Texas Microsystems
 1066  PicoPower Technology
 	0000  PT80C826
-	0001  PT86C52x [Vesuvius]
-	0002  PT80C524 [Nile]
+	0001  PT86C521 [Vesuvius v1] Host Bridge
+	0002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Master
+	0003  PT86C524 [Nile] PCI-to-PCI Bridge
+	0004  PT86C525 [Nile-II] PCI-to-PCI Bridge
 	0005  National PC87550 System Controller
-	8002  PT80C524 [Nile]
+	8002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave
 1067  Mitsubishi Electric
 	1002  VG500 [VolumePro Volume Rendering Accelerator]
 1068  Diversified Technology
@@ -1585,9 +1724,10 @@
 1087  Cache Computer
 1088  Microcomputer Systems (M) Son
 1089  Data General Corporation
-108a  Bit3 Computer Corp.
+108a  SBS Technologies (formerly Bit3 Computer Corp.)
 	0001  VME Bridge Model 617
 	0010  VME Bridge Model 618
+	0040  dataBLIZZARD
 	3000  VME Bridge Model 2706
 108c  Oakleigh Systems Inc.
 108d  Olicom
@@ -1689,6 +1829,7 @@
 		101e 0649  AMI MegaRAID IDE 100 Controller
 	0650  PBC0650A
 	0670  USB0670
+		1095 0670  USB0670
 	0673  USB0673
 	0680  PCI0680
 1096  Alacron
@@ -1702,18 +1843,23 @@
 109c  Megachips Corporation
 109d  Zida Technologies Ltd.
 109e  Brooktree Corporation
-	0350  Bt848 TV with DMA push
+	0350  Bt848 Video Capture
 	0351  Bt849A Video capture
+	0369  Bt878 Video Capture
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
 	036c  Bt879(??) Video Capture
 		13e9 0070  Win/TV (Video Section)
-	036e  Bt878
+	036e  Bt878 Video Capture
 		0070 13eb  WinTV/GO
 		0070 ff01  Viewcast Osprey 200
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Mediastream Controller NTSC
 		127a 0002  Bt878 Mediastream Controller PAL BG
 		127a 0003  Bt878a Mediastream Controller PAL BG
 		127a 0048  Bt878/832 Mediastream Controller
 		144f 3000  MagicTView CPH060 - Video
+		1461 0004  AVerTV WDM Video Capture
 		14f1 0001  Bt878 Mediastream Controller NTSC
 		14f1 0002  Bt878 Mediastream Controller PAL BG
 		14f1 0003  Bt878a Mediastream Controller PAL BG
@@ -1721,7 +1867,7 @@
 		1851 1850  FlyVideo'98 - Video
 		1851 1851  FlyVideo II
 		1852 1852  FlyVideo'98 - Video (with FM Tuner)
-	036f  Bt879
+	036f  Bt879 Video Capture
 		127a 0044  Bt879 Video Capture NTSC
 		127a 0122  Bt879 Video Capture PAL I
 		127a 0144  Bt879 Video Capture NTSC
@@ -1755,20 +1901,24 @@
 		1851 1850  FlyVideo'98
 		1851 1851  FlyVideo'98 EZ - video
 		1852 1852  FlyVideo'98 (with FM Tuner)
-	0878  Bt878
+	0878  Bt878 Audio Capture
 		0070 13eb  WinTV/GO
 		0070 ff01  Viewcast Osprey 200
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
+		11bd 001c  PCTV Sat (DBC receiver)
 		127a 0001  Bt878 Video Capture (Audio Section)
 		127a 0002  Bt878 Video Capture (Audio Section)
 		127a 0003  Bt878 Video Capture (Audio Section)
 		127a 0048  Bt878 Video Capture (Audio Section)
 		13e9 0070  Win/TV (Audio Section)
 		144f 3000  MagicTView CPH060 - Audio
+		1461 0004  AVerTV WDM Audio Capture
 		14f1 0001  Bt878 Video Capture (Audio Section)
 		14f1 0002  Bt878 Video Capture (Audio Section)
 		14f1 0003  Bt878 Video Capture (Audio Section)
 		14f1 0048  Bt878 Video Capture (Audio Section)
-	0879  Bt879 Video Capture (Audio Section)
+	0879  Bt879 Audio Capture
 		127a 0044  Bt879 Video Capture (Audio Section)
 		127a 0122  Bt879 Video Capture (Audio Section)
 		127a 0144  Bt879 Video Capture (Audio Section)
@@ -1795,7 +1945,7 @@
 		14f1 1522  Bt879 Video Capture (Audio Section)
 		14f1 1622  Bt879 Video Capture (Audio Section)
 		14f1 1722  Bt879 Video Capture (Audio Section)
-	0880  Bt880 Video Capture (Audio Section)
+	0880  Bt880 Audio Capture
 	2115  BtV 2115 Mediastream controller
 	2125  BtV 2125 Mediastream controller
 	2164  BtV 2164
@@ -1869,6 +2019,7 @@
 	1103  VScom 200 2 port serial adaptor
 	1146  VScom 010 1 port parallel adaptor
 	1147  VScom 020 2 port parallel adaptor
+	2724  Thales PCSM Security Card
 	9030  PCI <-> IOBus Bridge Hot Swap
 		15ed 1002  MCCS 8-port Serial Hot Swap
 		15ed 1003  MCCS 16-port Serial Hot Swap
@@ -1877,6 +2028,8 @@
 		10b5 2273  SH-ARC SoHard ARCnet card
 		1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem
 		1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem
+		1522 0003  RockForce 6 Port V.90 Data/Fax/Voice Modem
+		1522 0004  RockForce 8 Port V.90 Data/Fax/Voice Modem
 		1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem
 		1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem
 		15ed 1000  Macrolink MCCS 8-port Serial
@@ -1901,6 +2054,8 @@
 		d84d 4065  EX-4065 8S(16C550) RS-232
 		d84d 4068  EX-4068 8S(16C650) RS-232
 		d84d 4078  EX-4078 2S(16C552) RS-232+1P
+	9054  PCI <-> IOBus Bridge
+		10b5 2455  Wessex Techology PHIL-PCI
 	9060  9060
 	906d  9060SD
 		125c 0640  Aries 16000P
@@ -1937,6 +2092,7 @@
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
 	0001  3c985 1000BaseSX (SX/TX)
+	1006  MINI PCI type 3B Data Fax Modem
 	1007  Mini PCI 56k Winmodem
 		10b7 615c  Mini PCI 56K Modem
 	3390  3c339 TokenLink Velocity
@@ -1962,13 +2118,13 @@
 	6056  3c556B Hurricane CardBus
 		10b7 6556  10/100 Mini PCI Ethernet Adapter
 	6560  3CCFE656 Cyclone CardBus
-		10b7 656a  3CCFEM656 10/100 LAN 56K Modem CardBus
-	6561  3CCFEM656 10/100 LAN 56K Modem CardBus
-		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
+		10b7 656a  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6561  3CCFEM656 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6562  3CCFEM656 [id 6562] Cyclone CardBus
-		10b7 656b  3CCFEM656B 10/100 LAN 56K Modem CardBus
-	6563  3CCFEM656B 10/100 LAN 56K Modem CardBus
-		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
+		10b7 656b  3CCFEM656B 10/100 LAN+56K Modem CardBus
+	6563  3CCFEM656B 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
 	6564  3CCFEM656 [id 6564] Cyclone CardBus
 	7646  3cSOHO100-TX Hurricane
 	7940  3c803 FDDILink UTP Controller
@@ -2011,6 +2167,7 @@
 	9058  3c905B-Combo [Deluxe Etherlink XL 10/100]
 	905a  3c905B-FX [Fast Etherlink XL FX 10/100]
 	9200  3c905C-TX/TX-M [Tornado]
+		1028 0095  Integrated 3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 7000  10/100 Mini PCI Ethernet Adapter
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
@@ -2019,10 +2176,14 @@
 		10b7 1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
 		10b7 1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
 		10b7 9805  3c980 10/100baseTX NIC [Python-T]
+	9900  3C990-TX Typhoon
 	9902  3CR990-TX-95 56-bit Typhoon Client
 	9903  3CR990-TX-97 168-bit Typhoon Client
+	9904  3C990B-TX-M/3C990BSVR [Typhoon2]
+	9905  3CR990-FX-95/97/95 [Typhon Fiber]
 	9908  3CR990SVR95 56-bit Typhoon Server
 	9909  3CR990SVR97 Typhoon Server
+	990b  3C990SVR [Typhoon Server]
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
 		1055 e000  LANEPIC 10/100 [EVB171Q-PCI]
@@ -2089,7 +2250,7 @@
 	5219  M5219
 	5225  M5225
 	5229  M5229 IDE
-		1043 8053  A7A66 Motherboard IDE
+		1043 8053  A7A266 Motherboard IDE
 	5235  M5225
 	5237  USB 1.1 Controller
 	5239  USB 2.0 Controller
@@ -2207,12 +2368,13 @@
 	10dc  ATT2C15-3 FPGA
 10dd  Evans & Sutherland
 10de  nVidia Corporation
-	0008  EDGE 3D [NV1]
-	0009  EDGE 3D [NV1]
-	0010  Mutara V08 [NV2]
-	0020  Riva TnT [NV04]
+	0008  NV1 [EDGE 3D]
+	0009  NV1 [EDGE 3D]
+	0010  NV2 [Mutara V08]
+	0020  NV4 [Riva TnT]
 		1043 0200  V3400 TNT
 		1048 0c18  Erazor II SGRAM
+		1048 0c1b  Erazor II
 		1092 0550  Viper V550
 		1092 0552  Viper V550
 		1092 4804  Viper V550
@@ -2225,10 +2387,12 @@
 		1092 4904  Viper V550
 		1092 4914  Viper V550
 		1092 8225  Viper V550
+		10b4 273d  Velocity 4400
+		10b4 2740  Velocity 4400
 		10de 0020  Riva TNT
 		1102 1015  Graphics Blaster CT6710
 		1102 1016  Graphics Blaster RIVA TNT
-	0028  Riva TnT2 [NV5]
+	0028  NV5 [Riva TnT2]
 		1043 0200  AGP-V3800 SGRAM
 		1043 0201  AGP-V3800 SDRAM
 		1043 0205  PCI-V3800
@@ -2236,13 +2400,15 @@
 		1092 4804  Viper V770
 		1092 4a00  Viper V770
 		1092 4a02  Viper V770 Ultra
+		1092 5a00  RIVA TNT2/TNT2 Pro
 		1092 6a02  Viper V770 Ultra
 		1092 7a02  Viper V770 Ultra
 		10de 0005  RIVA TNT2 Pro
+		10de 000f  Compaq NVIDIA TNT2 Pro
 		1102 1020  3D Blaster RIVA TNT2
 		1102 1026  3D Blaster RIVA TNT2 Digital
 		14af 5810  Maxi Gamer Xentor
-	0029  Riva TnT2 Ultra [NV5]
+	0029  NV5 [Riva TnT2 Ultra]
 		1043 0200  AGP-V3800 Deluxe
 		1043 0201  AGP-V3800 Ultra SDRAM
 		1043 0205  PCI-V3800 Ultra
@@ -2250,82 +2416,97 @@
 		1102 1029  3D Blaster RIVA TNT2 Ultra
 		1102 102f  3D Blaster RIVA TNT2 Ultra
 		14af 5820  Maxi Gamer Xentor 32
-	002a  Riva TnT2 [NV5]
-	002b  Riva TnT2 [NV5]
-	002c  Vanta [NV6]
+	002a  NV5 [Riva TnT2]
+	002b  NV5 [Riva TnT2]
+	002c  NV6 [Vanta]
 		1043 0200  AGP-V3800 Combat SDRAM
 		1043 0201  AGP-V3800 Combat
 		1092 6820  Viper V730
 		1102 1031  CT6938 VANTA 8MB
 		1102 1034  CT6894 VANTA 16MB
 		14af 5008  Maxi Gamer Phoenix 2
-	002d  Vanta [NV6]
+	002d  RIVA TNT2 Model 64
 		1043 0200  AGP-V3800M
 		1043 0201  AGP-V3800M
 		1102 1023  CT6892 RIVA TNT2 Value
 		1102 1024  CT6932 RIVA TNT2 Value 32Mb
-		1102 102c  CT6931 RIVA TNT2 Value (Jumper)
+		1102 102c  CT6931 RIVA TNT2 Value [Jumper]
 		1462 8808  MSI-8808
-	002e  Vanta [NV6]
-	002f  Vanta [NV6]
-	00a0  Riva TNT2
+		1554 1041  PixelView RIVA TNT2 M64 32MB
+	002e  NV6 [Vanta]
+	002f  NV6 [Vanta]
+	00a0  NV5 [Riva TNT2]
 		14af 5810  Maxi Gamer Xentor
-	0100  NV10 (GeForce 256)
+	0100  NV10 [GeForce 256 SDR]
 		1043 0200  AGP-V6600 SGRAM
 		1043 0201  AGP-V6600 SDRAM
 		1043 4008  AGP-V6600 SGRAM
 		1043 4009  AGP-V6600 SDRAM
 		1102 102d  CT6941 GeForce 256
 		14af 5022  3D Prophet SE
-	0101  GeForce 256 DDR
+	0101  NV10 [GeForce 256 DDR]
 		1043 0202  AGP-V6800 DDR
 		1043 400a  AGP-V6800 DDR SGRAM
 		1043 400b  AGP-V6800 DDR SDRAM
 		1102 102e  CT6971 GeForce 256 DDR
 		14af 5021  3D Prophet DDR-DVI
-	0103  Quadro (GeForce 256 GL)
-	0110  NV11 (GeForce2 MX)
-		1043 4015  AGP-7100 Pro with TV output
+	0103  NV10 [Quadro]
+	0110  NV11 [GeForce2 MX]
+		1043 4015  AGP-V7100 Pro
 		1043 4031  V7100 Pro with TV output
-	0111  NV11 (GeForce2 MX DDR)
-	0112  GeForce2 Go
-	0113  NV11 (GeForce2 MXR)
-	0150  NV15 (GeForce2 Pro)
+		14af 7103  3D Prophet II MX Dual-Display
+	0111  NV11 [GeForce2 MX DDR]
+	0112  NV11 [GeForce2 Go]
+	0113  NV11 [GeForce2 MXR]
+	0150  NV15 [GeForce2 GTS]
 		1043 4016  V7700 AGP Video Card
 		107d 2840  WinFast GeForce2 GTS with TV output
 		1462 8831  Creative GeForce2 Pro
-	0151  NV15 DDR (GeForce2 GTS)
-	0152  NV15 Bladerunner (GeForce2 Ultra)
-	0153  NV15 GL (Quadro2 Pro)
-	0170  NV1x
-	0171  NV1x
-	0172  NV1x
+	0151  NV15 [GeForce2 Ti]
+	0152  NV15 [GeForce2 Ultra, Bladerunner]
+		1048 0c56  GLADIAC Ultra
+	0153  NV15 [Quadro2 Pro]
+	0170  NV17 [GeForce4 MX460]
+	0171  NV17 [GeForce4 MX440]
+	0172  NV17 [GeForce4 MX420]
 	0173  NV1x
-	0174  NV1x
-	0175  NV1x
-	0176  GeForce4 420 Go 32M
-	0178  NV1x
-	0179  GeForce4 440 Go 64M
-	017a  NV1x
-	017b  NV1x
-	017c  NV1x
-	01a0  GeForce2 Integrated GPU
+	0174  NV17 [GeForce4 440 Go]
+	0175  NV17 [GeForce4 420 Go]
+	0176  NV17 [GeForce4 420 Go 32M]
+	0178  Quadro4 500XGL
+	0179  NV17 [GeForce4 440 Go 64M]
+	017a  Quadro4 200/400NVS
+	017b  Quadro4 550XGL
+	017c  Quadro4 550 GoGL
+	01a0  NV15 [GeForce2 - nForce GPU]
+	01a4  nForce CPU bridge
+	01ab  nForce 420 Memory Controller (DDR)
+	01ac  nForce 220/420 Memory Controller
+	01ad  nForce 220/420 Memory Controller
+	01b1  nForce Audio
+	01b2  nForce ISA Bridge
+	01b4  nForce PCI System Management
+	01b7  nForce AGP to PCI Bridge
+	01b8  nForce PCI-to-PCI bridge
 	01bc  nForce IDE
-	0200  NV20 (GeForce3)
+	0200  NV20 [GeForce3]
 		1043 402f  AGP-V8200 DDR
-	0201  GeForce3 Ti200
-	0202  GeForce3 Ti500
+	0201  NV20 [GeForce3 Ti200]
+	0202  NV20 [GeForce3 Ti500]
 		1043 405b  V8200 T5
-	0203  Quadro DCC
-	0250  NV25 (GeForce 4)
-	0251  GeForce4 Ti 4400
-	0253  GeForce4 Ti 4200
-	0258  NV25 (GeForce 4)
-	025b  NV25 (GeForce 4)
+	0203  NV20 [Quadro DCC]
+	0250  NV25 [GeForce4 Ti4600]
+	0251  NV25 [GeForce4 Ti4400]
+	0253  NV25 [GeForce4 Ti4200]
+	0258  Quadro4 900XGL
+	0259  Quadro4 750XGL
+	025b  Quadro4 700XGL
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
 	f700  LP7000 Fibre Channel Host Adapter
+	f800  LP8000 Fibre Channel Host Adapter
+	f900  LP9000 Fibre Channel Host Adapter
 10e0  Integrated Micro Solutions Inc.
 	5026  IMS5026/27/28
 	5027  IMS5027
@@ -2376,8 +2557,8 @@
 	8111  Twist3 Frame Grabber
 10ec  Realtek Semiconductor Co., Ltd.
 	8029  RTL-8029(AS)
-		10b8 2011  EZ-Card
-		10ec 8029  RT8029(AS)
+		10b8 2011  EZ-Card (SMC1208)
+		10ec 8029  RTL-8029(AS)
 		1113 1208  EN1208
 		1186 0300  DE-528
 		1259 2400  AT-2400
@@ -2392,7 +2573,9 @@
 		10ec 8139  RT8139
 		1186 1300  DFE-538TX
 		1186 1320  SN5200
+		1186 8139  DRN-32TX
 		1259 2500  AT-2500TX
+		1259 2503  AT-2500TX/ACPI
 		1429 d010  ND010
 		1432 9130  EN-9130TX
 		1436 8139  RT8139
@@ -2413,6 +2596,8 @@
 	3fc1  RME Digi96/8
 	3fc2  RME Digi96/8 Pro
 	3fc3  RME Digi96/8 Pad
+	3fc4  RME Digi9652 (Hammerfall)
+	3fc5  RME Hammerfall DSP
 10ef  Racore Computer Products, Inc.
 	8154  M815x Token Ring Adapter
 10f0  Peritek Corporation
@@ -2454,34 +2639,45 @@
 		1102 8025  SBLive! Mainboard Implementation
 		1102 8026  CT4830 SBLive! Value
 		1102 8027  CT4832 SBLive! Value
+		1102 8028  CT4760 SBLive! OEM version
 		1102 8031  CT4831 SBLive! Value
 		1102 8040  CT4760 SBLive!
 		1102 8051  CT4850 SBLive! Value
+		1102 8061  SBLive! Player 5.1
 	0004  SB Audigy
+		1102 0051  SB0090 Audigy Player
 	4001  SB Audigy FireWire Port
 	7002  SB Live! MIDI/Game Port
 		1102 0020  Gameport Joystick
 	7003  SB Audigy MIDI/Game port
+		1102 0040  SB Audigy MIDI/Gameport
 	8938  ES1371
 1103  Triones Technologies, Inc.
 	0003  HPT343
-	0004  HPT366 / HPT370
+# Revisions: 01=HPT366, 03=HPT370, 04=HPT370A, 05=HPT372
+	0004  HPT366/368/370/370A/372
+		1103 0001  HPT370A
 		1103 0005  HPT370 UDMA100
-# Not HPT370A, It's HPT370. I don't know what ID HPT370A has.
-	0005  HPT370
+	0005  HPT372A
+	0006  HPT302
+	0007  HPT371
+	0008  HPT374
 1104  RasterOps Corp.
 1105  Sigma Designs, Inc.
+	1105  REALmagic Xcard MPEG 1/2/3/4 DVD Decoder
 	8300  REALmagic Hollywood Plus DVD Decoder
 	8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder
 1106  VIA Technologies, Inc.
+	0130  VT6305 1394.A Controller
 	0305  VT8363/8365 [KT133/KM133]
-		1043 8042  A7V133/A7V133-C
-		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard
 	0391  VT8371 [KX133]
 	0501  VT8501 [Apollo MVP4]
 	0505  VT82C505
 	0561  VT82C561
-	0571  Bus Master IDE
+	0571  VT82C586B PIPC Bus Master IDE
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -2496,7 +2692,8 @@
 	0605  VT8605 [ProSavage PM133]
 	0680  VT82C680 [Apollo P6]
 	0686  VT82C686 [Apollo Super South]
-		1043 8042  ATV133/A7V133-C
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
 		1106 0000  VT82C686/A PCI to ISA Bridge
 		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C693A/694x [Apollo PRO133x]
@@ -2508,9 +2705,11 @@
 	1106  VT82C570MV
 	1571  VT82C416MV
 	1595  VT82C595/97 [Apollo VP2/97]
-	3038  UHCI USB
+	3038  USB
+		0925 1234  USB Controller
+		1234 0925  MVP3 USB Controller
 	3040  VT82C586B ACPI
-	3043  VT3043 [Rhine]
+	3043  VT86C100A [Rhine]
 		10bd 0000  VT86C100A Fast Ethernet Adapter
 		1106 0100  VT86C100A Fast Ethernet Adapter
 		1186 1400  DFE-530TX rev A
@@ -2518,10 +2717,14 @@
 	3050  VT82C596 Power Management
 	3051  VT82C596 Power Management
 	3057  VT82C686 [Apollo Super ACPI]
-		1043 8042  ATV133/A7V133-C
+		1043 8033  A7V Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
 	3058  VT82C686 AC97 Audio Controller
+		0e11 b194  Soundmax integrated digital audio
+		1106 4511  Onboard Audio on EP7KXA
 		1458 7600  Onboard Audio
 		1462 3091  MS-6309 Onboard Audio
+		15dd 7609  Onboard Audio
 	3059  VT8233 AC97 Audio Controller
 	3065  VT6102 [Rhine-II]
 		1186 1400  DFE-530TX rev A
@@ -2530,13 +2733,24 @@
 	3074  VT8233 PCI to ISA Bridge
 	3091  VT8633 [Apollo Pro266]
 	3099  VT8367 [KT266]
+		1043 8064  A7V266-E
+		1043 807f  A7V333
+	3101  VT8653 Host Bridge
+	3102  VT8662 Host Bridge
+	3103  VT8615 Host Bridge
 	3104  USB 2.0
 	3109  VT8233C PCI to ISA Bridge
+	3112  VT8361 [KLE133] Host Bridge
 	3128  VT8753 [P4X266 AGP]
+	3133  VT3133 Host Bridge
+	3147  VT8233A ISA Bridge
+	3148  P4M266 Host Bridge
+	3156  P/KN266 Host Bridge
+	3177  VT8233A ISA Bridge
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
-	8235  VT8235 Power Management
+	8235  VT8235 ACPI
 	8305  VT8363/8365 [KT133/KM133 AGP]
 	8391  VT8371 [KX133 AGP]
 	8501  VT8501 [Apollo MVP4 AGP]
@@ -2546,8 +2760,13 @@
 	8601  VT8601 [Apollo ProMedia AGP]
 	8605  VT8605 [PM133 AGP]
 	8691  VT82C691 [Apollo Pro]
+	8693  VT82C693 [Apollo Pro Plus] PCI Bridge
 	b091  VT8633 [Apollo Pro266 AGP]
-	b099  VT8367 [KT266 AGP]
+	b099  VT8367 [KT333 AGP]
+	b101  VT8653 AGP Bridge
+	b102  VT8362 AGP Bridge
+	b103  VT8615 AGP Bridge
+	b112  VT8361 [KLE133] AGP Bridge
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -2714,9 +2933,10 @@
 	0200  ForeRunner PCA-200 ATM
 	0210  PCA-200PC
 	0250  ATM
-	0300  PCA-200E
+	0300  ForeRunner PCA-200EPC ATM
 	0310  ATM
 	0400  ForeRunnerHE ATM Adapter
+		1127 0400  ForeRunnerHE ATM
 1129  Firmworks
 112a  Hermes Electronics Company, Ltd.
 112b  Linotype - Hell AG
@@ -2728,6 +2948,9 @@
 	0001  MVC IM-PCI Video frame grabber/processor
 1130  Computervision
 1131  Philips Semiconductors
+	7130  SAA7130 Video Broadcast Decoder
+# PCI audio and video broadcast decoder (http://www.semiconductors.philips.com/pip/saa7134hl)
+	7134  SAA7134
 	7145  SAA7145
 	7146  SAA7146
 		114b 2003  DVRaptor Video Edit/Capture Card
@@ -2762,6 +2985,7 @@
 		1133 e012  DIVA Server BRI-8M
 	e014  DIVA Server PRI-30M
 		1133 e014  DIVA Server PRI-30M
+	e018  DIVA Server BRI-2M/-2F
 1134  Mercury Computer Systems
 	0001  Raceway Bridge
 1135  Fuji Xerox Co Ltd
@@ -2832,6 +3056,7 @@
 		1148 9844  SK-9844 (1000Base-SX dual link)
 		1148 9861  SK-9861 (1000Base-SX VF45 single link)
 		1148 9862  SK-9862 (1000Base-SX VF45 dual link)
+	4400  Gigabit Ethernet
 1149  Win System Corporation
 114a  VMIC
 	5579  VMIPCI-5579 (Reflective Memory Card)
@@ -2904,6 +3129,7 @@
 		1014 9181  10/100 EtherJet Cardbus Adapter
 		115d 0181  Cardbus Ethernet 10/100
 		115d 1181  Cardbus Ethernet 10/100
+		1179 0181  Cardbus Ethernet 10/100
 		8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 		8086 9181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
 	0005  Cardbus Ethernet 10/100
@@ -2926,6 +3152,8 @@
 	0101  Cardbus 56k modem
 		115d 1081  Cardbus 56k Modem
 	0103  Cardbus Ethernet + 56k Modem
+		1014 9181  Cardbus 56k Modem
+		1115 1181  Cardbus Ethernet 100 + 56k Modem
 		115d 1181  CBEM56G-100 Ethernet + 56k Modem
 		8086 9181  PRO/100 LAN + Modem56 CardBus
 115e  Peer Protocols Inc
@@ -2941,16 +3169,27 @@
 1165  Imagraph Corporation
 	0001  Motion TPEG Recorder/Player with audio
 1166  ServerWorks
+	0005  CNB20-LE Host Bridge
 	0007  CNB20-LE Host Bridge
 	0008  CNB20HE Host Bridge
 	0009  CNB20LE Host Bridge
 	0010  CIOB30
 	0011  CMIC-HE
+	0013  CNB20-HE Host Bridge
+	0014  CNB20-HE Host Bridge
+	0015  CMIC-GC Host Bridge
+	0016  CMIC-GC Host Bridge
+	0017  GCNB-LE Host Bridge
 	0200  OSB4 South Bridge
 	0201  CSB5 South Bridge
+	0203  CSB6 South Bridge
 	0211  OSB4 IDE Controller
 	0212  CSB5 IDE Controller
-	0220  OSB4/CSB5 USB Controller
+	0213  CSB6 RAID/IDE Controller
+	0220  OSB4/CSB5 OHCI USB Controller
+	0221  CSB6 OHCI USB Controller
+	0225  GCLE Host Bridge
+	0227  GCLE-2 Host Bridge
 1167  Mutoh Industries Inc
 1168  Thine Electronics Inc
 1169  Centre for Development of Advanced Computing
@@ -2975,6 +3214,7 @@
 1178  Alfa, Inc.
 	afa1  Fast Ethernet Adapter
 1179  Toshiba America Info Systems
+	0103  EX-IDE Type-B
 	0404  DVD Decoder card
 	0406  Tecra Video Capture device
 	0407  DVD Decoder card (Version 2)
@@ -2986,6 +3226,8 @@
 	0618  CPU to PCI and PCI to ISA bridge
 # Claimed to be Lucent DSP1645 [Mars], but that's apparently incorrect. Does anyone know the correct ID?
 	0701  FIR Port
+	0804  TC6371AF SmartMedia Controller
+	0805  SD TypA Controller
 	0d01  FIR Port Type-DO
 		1179 0001  FIR Port Type-DO
 117a  A-Trend Technology
@@ -2999,8 +3241,14 @@
 	0466  RL5c466
 	0475  RL5c475
 	0476  RL5c476 II
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	0477  RL5c477
 	0478  RL5c478
+		1014 0184  ThinkPad A30p (2653-64G)
+	0522  R5C522 IEEE 1394 Controller
+		1014 01cf  ThinkPad A30p (2653-64G)
+	0551  R5C551 IEEE 1394 Controller
 	0552  R5C552 IEEE 1394 Controller
 1181  Telmatics International
 1183  Fujikura Ltd
@@ -3008,8 +3256,12 @@
 1185  Dataworld International Ltd
 1186  D-Link System Inc
 	0100  DC21041
-	1002  Sundance Ethernet
+	1002  DL10050 Sundance Ethernet
+		1186 1002  DFE-550TX
+		1186 1012  DFE-580TX
 	1300  RTL8139 Ethernet
+		1186 1300  DFE-538TX 10/100 Ethernet Adapter
+		1186 1301  DFE-530TX+ 10/100 Ethernet Adapter
 	1340  DFE-690TXD CardBus PC Card
 	1561  DRP-32TXD Cardbus PC Card
 	4000  DL2K Ethernet
@@ -3101,6 +3353,7 @@
 		11ad ffff  LNE100TX
 		1385 f004  FA310TX
 	c115  LNE100TX [Linksys EtherFast 10/100]
+		11ad c001  LNE100TX [ver 2.0]
 11ae  Aztech System Ltd
 11af  Avid Technology Inc.
 11b0  V3 Semiconductor Inc.
@@ -3199,6 +3452,7 @@
 		13e0 0041  TelePath Internet 56k WinModem
 		1436 0440  Lucent Win Modem
 		144f 0449  Lucent 56k V.90 DFi Modem
+		1468 0410  IBM ThinkPad T23 (2647-4MG)
 		1468 0440  Lucent Win Modem
 		1468 0449  Presario 56k V.90 DFi Modem
 	044a  F-1156IV WinModem (V90, 56KFlex)
@@ -3225,6 +3479,8 @@
 	0461  V90 WildWire Modem
 	0462  V90 WildWire Modem
 	0480  Venus Modem (V90, 56KFlex)
+	5801  USB
+	5802  USS-312 USB Controller
 	5811  FW323
 		dead 0800  FireWire Host Bus Adapter
 11c2  Sand Microelectronics
@@ -3313,6 +3569,7 @@
 	0113  FreedomLine 100
 	1401  ReadyLink 2000
 	2011  RL100-ATX 10/100
+		11f6 2011  RL100-ATX
 	2201  ReadyLink 100TX (Winbond W89C840)
 		11f6 2011  ReadyLink 100TX
 	9881  RL100TX
@@ -3331,11 +3588,13 @@
 	0004  RocketPort 32 Intf
 	0005  RocketPort Octacable
 	0006  RocketPort 8J
+	0007  RocketPort 4-port
 	0008  RocketPort 8-port
 	0009  RocketPort 16-port
 	000a  RocketPort Plus Quadcable
 	000b  RocketPort Plus Octacable
 	000c  RocketPort 8-port Modem
+	8015  RocketPort 4-port UART 16954
 11ff  Scion Corporation
 1200  CSS Corporation
 1201  Vista Controls Corp
@@ -3352,18 +3611,21 @@
 120c  Technical Corp.
 120d  Compression Labs, Inc.
 120e  Cyclades Corporation
-	0100  Cyclom_Y below first megabyte
-	0101  Cyclom_Y above first megabyte
-	0102  Cyclom_4Y below first megabyte
-	0103  Cyclom_4Y above first megabyte
-	0104  Cyclom_8Y below first megabyte
-	0105  Cyclom_8Y above first megabyte
-	0200  Cyclom_Z below first megabyte
-	0201  Cyclom_Z above first megabyte
-	0300  PC300 RX 2
-	0301  PC300 RX 1
-	0310  PC300 TE 2
-	0311  PC300 TE 1
+	0100  Cyclom-Y below first megabyte
+	0101  Cyclom-Y above first megabyte
+	0102  Cyclom-4Y below first megabyte
+	0103  Cyclom-4Y above first megabyte
+	0104  Cyclom-8Y below first megabyte
+	0105  Cyclom-8Y above first megabyte
+	0200  Cyclades-Z below first megabyte
+	0201  Cyclades-Z above first megabyte
+	0300  PC300/RSV or /X21 (2 ports)
+	0301  PC300/RSV or /X21 (1 port)
+	0310  PC300/TE (2 ports)
+	0311  PC300/TE (1 port)
+	0320  PC300/TE-M (2 ports)
+	0321  PC300/TE-M (1 port)
+	0400  PC400
 120f  Essential Communications
 	0001  Roadrunner serial HIPPI
 1210  Hyperparallel Technologies
@@ -3374,12 +3636,15 @@
 1215  Interware Co., Ltd
 1216  Purup Prepress A/S
 1217  O2 Micro, Inc.
-	6729  6729
-	673a  6730
-	6832  6832
-	6836  6836
+	6729  OZ6729
+	673a  OZ6730
+	6832  OZ6832/6833 Cardbus Controller
+	6836  OZ6836/6860 Cardbus Controller
 	6872  OZ6812 Cardbus Controller
+	6925  OZ6922 Cardbus Controller
 	6933  OZ6933 Cardbus Controller
+		1025 1016  Travelmate 612 TX
+	6972  OZ6912 Cardbus Controller
 1218  Hybricon Corp.
 1219  First Virtual Corporation
 121a  3Dfx Interactive, Inc.
@@ -3493,7 +3758,10 @@
 1240  Marathon Technologies Corp.
 1241  DSC Communications
 1242  Jaycor Networks, Inc.
+	1242  JNI Corporation (former Jaycor Networks, Inc.)
 	4643  FCI-1063 Fibre Channel Adapter
+	6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter
+	656a  FCX-6562 PCI-X Fibre Channel Adapter
 1243  Delphax
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
@@ -3543,6 +3811,7 @@
 125b  Asix Electronics Corporation
 	1400  ALFA GFC2204
 125c  Aurora Technologies, Inc.
+	0640  Aries 16000P
 125d  ESS Technology
 	0000  ES336H Fax Modem (Early Model)
 	1948  Solo?
@@ -3583,6 +3852,8 @@
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
 1260  Harris Semiconductor
+	3873  Prism 2.5 Wavelan chipset
+		1186 3501  DWL-520 Wireless PCI Adapter
 	8130  HMP8130 NTSC/PAL Video Decoder
 	8131  HMP8131 NTSC/PAL Video Decoder
 1261  Matsushita-Kotobuki Electronics Industries, Ltd.
@@ -3619,6 +3890,7 @@
 	0002  DirecPC
 1274  Ensoniq
 	1371  ES1371 [AudioPCI-97]
+		0e11 0024  AudioPCI on Motherboard Compaq Deskpro
 		0e11 b1a7  ES1371, ES1373 AudioPCI
 		1033 80ac  ES1371, ES1373 AudioPCI
 		1042 1854  Tazer
@@ -3695,70 +3967,70 @@
 127a  Rockwell International
 	1002  HCF 56k Data/Fax Modem
 		1092 094c  SupraExpress 56i PRO [Diamond SUP2380]
-		122d 4002  HPG / MDP3858-U # Aztech
-		122d 4005  MDP3858-E # Aztech
-		122d 4007  MDP3858-A/-NZ # Aztech
-		122d 4012  MDP3858-SA # Aztech
-		122d 4017  MDP3858-W # Aztech
-		122d 4018  MDP3858-W # Aztech
+		122d 4002  HPG / MDP3858-U
+		122d 4005  MDP3858-E
+		122d 4007  MDP3858-A/-NZ
+		122d 4012  MDP3858-SA
+		122d 4017  MDP3858-W
+		122d 4018  MDP3858-W
 		127a 1002  Rockwell 56K D/F HCF Modem
 	1003  HCF 56k Data/Fax Modem
-		0e11 b0bc  229-DF Zephyr # Compaq
-		0e11 b114  229-DF Cheetah # Compaq
-		1033 802b  229-DF # NEC
-		13df 1003  PCI56RX Modem # E-Tech Inc
-		13e0 0117  IBM # GVC
-		13e0 0147  IBM # GVC F-1156IV /R3 Spain V.90 Modem
-		13e0 0197  IBM # GVC
-		13e0 01c7  IBM # GVC F-1156IV /R3 WW V.90 Modem
-		13e0 01f7  IBM # GVC
-		1436 1003  IBM # CIS
-		1436 1103  IBM # CIS 5614PM3G V.90 Modem
+		0e11 b0bc  229-DF Zephyr
+		0e11 b114  229-DF Cheetah
+		1033 802b  229-DF
+		13df 1003  PCI56RX Modem
+		13e0 0117  IBM
+		13e0 0147  IBM F-1156IV+/R3 Spain V.90 Modem
+		13e0 0197  IBM
+		13e0 01c7  IBM F-1156IV+/R3 WW V.90 Modem
+		13e0 01f7  IBM
+		1436 1003  IBM
+		1436 1103  IBM 5614PM3G V.90 Modem
 		1436 1602  Compaq 229-DF Ducati
 	1004  HCF 56k Data/Fax/Voice Modem
 		1048 1500  MicroLink 56k Modem
 		10cf 1059  Fujitsu 229-DFRT
 	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
-		1033 8029  229-DFSV # NEC
-		1033 8054  Modem # NEC
+		1033 8029  229-DFSV
+		1033 8054  Modem
 		10cf 103c  Fujitsu
 		10cf 1055  Fujitsu 229-DFSV
 		10cf 1056  Fujitsu 229-DFSV
-		122d 4003  MDP3858SP-U # Aztech
-		122d 4006  Packard Bell MDP3858V-E # Aztech
-		122d 4008  MDP3858SP-A/SP-NZ # Aztech
-		122d 4009  MDP3858SP-E # Aztech
-		122d 4010  MDP3858V-U # Aztech
-		122d 4011  MDP3858SP-SA # Aztech
-		122d 4013  MDP3858V-A/V-NZ # Aztech
-		122d 4015  MDP3858SP-W # Aztech
-		122d 4016  MDP3858V-W # Aztech
-		122d 4019  MDP3858V-SA # Aztech
-		13df 1005  PCI56RVP Modem  # E-Tech Inc
-		13e0 0187  IBM # GVC
-		13e0 01a7  IBM # GVC
-		13e0 01b7  IBM # GVC DF-1156IV /R3 Spain V.90 Modem
-		13e0 01d7  IBM # GVC DF-1156IV /R3 WW V.90 Modem
-		1436 1005  IBM # CIS
-		1436 1105  IBM # CIS
-		1437 1105  IBM # CIS 5614PS3G V.90 Modem
+		122d 4003  MDP3858SP-U
+		122d 4006  Packard Bell MDP3858V-E
+		122d 4008  MDP3858SP-A/SP-NZ
+		122d 4009  MDP3858SP-E
+		122d 4010  MDP3858V-U
+		122d 4011  MDP3858SP-SA
+		122d 4013  MDP3858V-A/V-NZ
+		122d 4015  MDP3858SP-W
+		122d 4016  MDP3858V-W
+		122d 4019  MDP3858V-SA
+		13df 1005  PCI56RVP Modem
+		13e0 0187  IBM
+		13e0 01a7  IBM
+		13e0 01b7  IBM DF-1156IV+/R3 Spain V.90 Modem
+		13e0 01d7  IBM DF-1156IV+/R3 WW V.90 Modem
+		1436 1005  IBM
+		1436 1105  IBM
+		1437 1105  IBM 5614PS3G V.90 Modem
 	1022  HCF 56k Modem
 		1436 1303  M3-5614PM3G V.90 Modem
 	1023  HCF 56k Data/Fax Modem
-		122d 4020  Packard Bell MDP3858-WE # Aztech
-		122d 4023  MDP3858-UE # Aztech
-		13e0 0247  IBM # GVC F-1156IV /R6 Spain V.90 Modem
-		13e0 0297  IBM # GVC
-		13e0 02c7  IBM # GVC F-1156IV /R6 WW V.90 Modem
-		1436 1203  IBM # CIS
-		1436 1303  IBM # CIS
+		122d 4020  Packard Bell MDP3858-WE
+		122d 4023  MDP3858-UE
+		13e0 0247  IBM F-1156IV+/R6 Spain V.90 Modem
+		13e0 0297  IBM
+		13e0 02c7  IBM F-1156IV+/R6 WW V.90 Modem
+		1436 1203  IBM
+		1436 1303  IBM
 	1024  HCF 56k Data/Fax/Voice Modem
 	1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 106a  Fujitsu 235-DFSV
-		122d 4021  Packard Bell MDP3858V-WE # Aztech
-		122d 4022  MDP3858SP-WE # Aztech
-		122d 4024  MDP3858V-UE # Aztech
-		122d 4025  MDP3858SP-UE # Aztech
+		122d 4021  Packard Bell MDP3858V-WE
+		122d 4022  MDP3858SP-WE
+		122d 4024  MDP3858V-UE
+		122d 4025  MDP3858SP-UE
 	1026  HCF 56k PCI Speakerphone Modem
 	1032  HCF 56k Modem
 	1033  HCF 56k Modem
@@ -3767,30 +4039,30 @@
 	1036  HCF 56k Modem
 	1085  HCF 56k Volcano PCI Modem
 	2005  HCF 56k Data/Fax Modem
-		104d 8044  229-DFSV # Sony
-		104d 8045  229-DFSV # Sony
-		104d 8055  PBE/Aztech 235W-DFSV # Sony
-		104d 8056  235-DFSV # Sony
-		104d 805a  Modem # Sony
-		104d 805f  Modem # Sony
-		104d 8074  Modem # Sony
+		104d 8044  229-DFSV
+		104d 8045  229-DFSV
+		104d 8055  PBE/Aztech 235W-DFSV
+		104d 8056  235-DFSV
+		104d 805a  Modem
+		104d 805f  Modem
+		104d 8074  Modem
 	2013  HSF 56k Data/Fax Modem
-		1179 0001  Modem # Toshiba
-		1179 ff00  Modem # Toshiba
+		1179 0001  Modem
+		1179 ff00  Modem
 	2014  HSF 56k Data/Fax/Voice Modem
 		10cf 1057  Fujitsu Citicorp III
-		122d 4050  MSP3880-U # Aztech
-		122d 4055  MSP3880-W # Aztech
+		122d 4050  MSP3880-U
+		122d 4055  MSP3880-W
 	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 1063  Fujitsu
 		10cf 1064  Fujitsu
 		1468 2015  Fujitsu
 	2016  HSF 56k Data/Fax/Voice/Spkp Modem
-		122d 4051  MSP3880V-W # Aztech
-		122d 4052  MSP3880SP-W # Aztech
-		122d 4054  MSP3880V-U # Aztech
-		122d 4056  MSP3880SP-U # Aztech
-		122d 4057  MSP3880SP-A # Aztech
+		122d 4051  MSP3880V-W
+		122d 4052  MSP3880SP-W
+		122d 4054  MSP3880V-U
+		122d 4056  MSP3880SP-U
+		122d 4057  MSP3880SP-A
 	4311  Riptide HSF 56k PCI Modem
 		127a 4311  Ring Modular? Riptide HSF RT HP Dom
 		13e0 0210  HP-GVC
@@ -3800,7 +4072,7 @@
 		1235 4321  Hewlett Packard DF
 		1235 4324  Hewlett Packard DF
 		13e0 0210  Hewlett Packard DF
-		144d 2321  Riptide # Samsung
+		144d 2321  Riptide
 	4322  Riptide PCI Game Controller
 		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
@@ -3878,7 +4150,7 @@
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
-	0001  AceNIC Gigabit Ethernet (Fibre)
+	0001  AceNIC Gigabit Ethernet
 		12ae 0001  Gigabit Ethernet-SX (Universal)
 		1410 0104  Gigabit Ethernet-SX PCI Adapter
 	0002  AceNIC Gigabit Ethernet (Copper)
@@ -3929,6 +4201,8 @@
 	5598  PCI NE2K Ethernet
 12c4  Connect Tech Inc
 12c5  Picture Elements Incorporated
+	007e  Imaging/Scanning Subsystem Engine
+	007f  Imaging/Scanning Subsystem Engine
 	0081  PCIVST [Grayscale Thresholding Engine]
 	0085  Video Simulator/Sender
 	0086  THR2 Multi-scale Thresholder
@@ -4006,6 +4280,7 @@
 		1092 2100  Sonic Impact A3D
 		1092 2110  Sonic Impact A3D
 		1092 2200  Sonic Impact A3D
+		122d 1002  AU8820 Vortex Digital Audio Processor
 		12eb 0001  AU8820 Vortex Digital Audio Processor
 		5053 3355  Montego
 	0002  Vortex 2
@@ -4226,6 +4501,7 @@
 135a  Brain Boxes
 135b  Giganet Inc
 135c  Quatech Inc
+	00f0  MPAC-100 Syncronous Serial Card (Zilog 85230)
 135d  ABB Network Partner AB
 135e  Sealevel Systems Inc
 	7101  Single Port RS-232/422/485/530
@@ -4299,6 +4575,7 @@
 	3200  Intellio C320 Turbo PCI
 1394  Level One Communications
 	0001  LXT1001 Gigabit Ethernet
+		1394 0001  NetCelerator Adapter
 1395  Ambicom Inc
 1396  Cipher Systems Inc
 1397  Cologne Chip Designs GmbH
@@ -4308,6 +4585,9 @@
 1398  Clarion co. Ltd
 1399  Rios systems Co Ltd
 139a  Alacritech Inc
+	0001  Quad Port 10/100 Server Accelerator
+	0003  Single Port 10/100 Server Accelerator
+	0005  Single Port Gigabit Server Accelerator
 139b  Mediasonic Multimedia Systems Ltd
 139c  Quantum 3d Inc
 139d  EPL limited
@@ -4355,6 +4635,7 @@
 13c1  3ware Inc
 	1000  3ware ATA-RAID
 	1001  3ware 7000-series ATA-RAID
+	1002  3ware ATA-RAID
 13c2  Technotrend Systemtechnik GmbH
 13c3  Janz Computer AG
 13c4  Phase Metrics
@@ -4405,7 +4686,7 @@
 13ee  Hayes Microcomputer Products Inc
 13ef  Coppercom Inc
 13f0  Sundance Technology Inc
-	0201  Sundance Ethernet
+	0201  ST201 Sundance Ethernet
 13f1  Oce' - Technologies B.V.
 13f2  Ford Microelectronics Inc
 13f3  Mcdata Corporation
@@ -4419,6 +4700,7 @@
 		13f6 0101  CMI8338-031 PCI Audio Device
 	0111  CM8738
 		1043 8077  CMI8738 6-channel audio controller
+		1043 80e2  CMI8738 6ch-MX
 		13f6 0111  CMI8738/C3DX PCI Audio Device
 	0211  CM8738
 13f7  Wildfire Communications
@@ -4429,6 +4711,7 @@
 13fc  Computer Peripherals International
 13fd  Micro Science Inc
 13fe  Advantech Co. Ltd
+	1756  PCI-1756
 13ff  Silicon Spice Inc
 1400  Artx Inc
 	1401  9432 TX
@@ -4448,6 +4731,7 @@
 	0500  Lava Single Serial
 	0600  Lava Port 650
 	8000  Lava Parallel
+	8001  Dual parallel port controller A
 	8002  Lava Dual Parallel port A
 	8003  Lava Dual Parallel port B
 	8800  BOCA Research IOPPAR
@@ -4468,9 +4752,11 @@
 1414  Microsoft Corporation
 1415  Oxford Semiconductor Ltd
 	8403  VScom 011H-EP1 1 port parallel adaptor
-	9501  Quad 16950 UART
+	9501  OX16PCI954 (Quad 16950 UART) function 0
 		15ed 2000  MCCR Serial p0-3 of 8
 		15ed 2001  MCCR Serial p0-3 of 16
+	950a  EXSYS EX-41092 Dual 16950 Serial adapter
+	950b  OXCB950 Cardbus 16950 UART
 	9511  OX16PCI954 (Quad 16950 UART) function 1
 		15ed 2000  MCCR Serial p4-7 of 8
 		15ed 2001  MCCR Serial p4-15 of 16
@@ -4717,18 +5003,21 @@
 	0007  PCI224
 	0008  PCI234
 	0009  PCI236
+	000a  PCI272
+	000b  PCI215
 14dd  Boulder Design Labs Inc
 14de  Applied Integration Corporation
 14df  ASIC Communications Corp
 14e1  INVERTEX
 14e2  INFOLIBRIA
 14e3  AMTELCO
-14e4  BROADCOM Corporation
+14e4  Broadcom Corporation
 	1644  NetXtreme BCM5700 Gigabit Ethernet
-		1014 0277  Vigil B5700 1000BaseTX
-		1028 00d1  NetXtreme 1000BaseTX
-		1028 0106  NetXtreme 1000BaseTX
-		1028 0109  NetXtreme 1000BaseTX
+		1014 0277  Broadcom Vigil B5700 1000BaseTX
+		1028 00d1  Broadcom BCM5700
+		1028 0106  Broadcom BCM5700
+		1028 0109  Broadcom BCM5700 1000BaseTX
+		1028 010a  Broadcom BCM5700 1000BaseTX
 		10b7 1000  3C996-T 1000BaseTX
 		10b7 1001  3C996B-T 1000BaseTX
 		10b7 1002  3C996C-T 1000BaseTX
@@ -4740,47 +5029,49 @@
 		14e4 0003  NetXtreme 1000BaseSX
 		14e4 0004  NetXtreme 1000BaseTX
 		14e4 1028  NetXtreme 1000BaseTX
-		14e4 1644  NetXtreme BCM5700 1000BaseTX
+		14e4 1644  BCM5700 1000BaseTX
 	1645  NetXtreme BCM5701 Gigabit Ethernet
 		0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
 		0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
 		0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)
 		0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)
 		0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
-		1028 0121  NetXtreme BCM5701 1000BaseTX
+		1028 0121  Broadcom BCM5701 1000BaseTX
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1006  3C996B-T 1000BaseTX
 		10b7 1007  3C1000-T 1000BaseTX
 		10b7 1008  3C940-BR01 1000BaseTX
-		14e4 0001  NetXtreme BCM5701 1000BaseTX
-		14e4 0005  NetXtreme BCM5701 1000BaseTX
-		14e4 0006  NetXtreme BCM5701 1000BaseTX
-		14e4 0007  NetXtreme BCM5701 1000BaseSX
-		14e4 0008  NetXtreme BCM5701 1000BaseTX
-		14e4 8008  NetXtreme BCM5701 1000BaseTX
+		14e4 0001  BCM5701 1000BaseTX
+		14e4 0005  BCM5701 1000BaseTX
+		14e4 0006  BCM5701 1000BaseTX
+		14e4 0007  BCM5701 1000BaseSX
+		14e4 0008  BCM5701 1000BaseTX
+		14e4 8008  BCM5701 1000BaseTX
 	1646  NetXtreme BCM5702 Gigabit Ethernet
 		0e11 00bb  NC7760 1000BaseTX
-		1028 0126  NetXtreme BCM5702 1000BaseTX
-		14e4 8009  NetXtreme BCM5702 1000BaseTX
+		1028 0126  Broadcom BCM5702 1000BaseTX
+		14e4 8009  BCM5702 1000BaseTX
 	1647  NetXtreme BCM5703 Gigabit Ethernet
 		0e11 0099  NC7780 1000BaseTX
 		0e11 009a  NC7770 1000BaseTX
-		14e4 0009  NetXtreme BCM5703 1000BaseTX
-		14e4 000a  NetXtreme BCM5703 1000BaseSX
-		14e4 000b  NetXtreme BCM5703 1000BaseTX
-		14e4 8009  NetXtreme BCM5703 1000BaseTX
-		14e4 800a  NetXtreme BCM5703 1000BaseTX
+		14e4 0009  BCM5703 1000BaseTX
+		14e4 000a  BCM5703 1000BaseSX
+		14e4 000b  BCM5703 1000BaseTX
+		14e4 8009  BCM5703 1000BaseTX
+		14e4 800a  BCM5703 1000BaseTX
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
 	4212  BCM v.90 56k modem
 	5820  BCM5820 Crypto Accelerator
+	5821  BCM5821 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
 14e7  3CX
 14e8  RAYCER Inc
 14e9  GARNETS System CO Ltd
-14ea  PLANEX COMMUNICATIONS Inc
+14ea  Planex Communications, Inc
+	ab06  FNW-3603-TX CardBus Fast Ethernet
 14eb  SEIKO EPSON Corp
 14ec  ACQIRIS
 14ed  DATAKINETICS Ltd
@@ -4806,12 +5097,12 @@
 		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem
 		13e0 020d  Dell Copper
 		13e0 020e  Dell Silver
-		13e0 0261  IBM # GVC
+		13e0 0261  IBM
 		13e0 0290  Compaq Goldwing
-		13e0 02a0  IBM # GVC
-		13e0 02b0  IBM # GVC
+		13e0 02a0  IBM
+		13e0 02b0  IBM
 		13e0 02c0  Compaq Scooter
-		13e0 02d0  IBM # GVC
+		13e0 02d0  IBM
 		144f 1500  IBM P85-DF (1)
 		144f 1501  IBM P85-DF (2)
 		144f 150a  IBM P85-DF (3)
@@ -4845,8 +5136,8 @@
 	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 	1436  HCF 56k Data/Fax Modem
 	1453  HCF 56k Data/Fax Modem
-		13e0 0240  IBM # GVC
-		13e0 0250  IBM # GVC
+		13e0 0240  IBM
+		13e0 0250  IBM
 		144f 1502  IBM P95-DF (1)
 		144f 1503  IBM P95-DF (2)
 	1454  HCF 56k Data/Fax/Voice Modem
@@ -4854,6 +5145,8 @@
 	1456  HCF 56k Data/Fax/Voice/Spkp Modem
 		122d 4035  Dell Europa - MDP3900V-W
 		122d 4302  Dell MP3930V-W(C) MiniPCI
+	1610  ADSL AccessRunner PCI Arbitration Device
+	1611  AccessRunner PCI ADSL Interface Device
 	1803  HCF 56k Modem
 		0e11 0023  623-LAN Grizzly
 		0e11 0043  623-LAN Yogi
@@ -4903,9 +5196,9 @@
 	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
 	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)
 	2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)
-		104d 8075  Modem # Sony
-		104d 8083  Modem # Sony
-		104d 8097  Modem # Sony
+		104d 8075  Modem
+		104d 8083  Modem
+		104d 8097  Modem
 	2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)
 	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)
 	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)
@@ -4916,6 +5209,8 @@
 	2f00  HSF 56k HSFi Modem
 		13e0 8d84  IBM HSFi V.90
 		13e0 8d85  Compaq Stinger
+		14f1 2004  Dynalink 56PMi
+	8234  RS8234 ATM SAR Controller [ServiceSAR Plus]
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -4963,6 +5258,8 @@
 1514  TFL LAN Inc
 1515  Advent design
 1516  MYSON Technology Inc
+	0803  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
+		1320 10bd  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
 1517  ECHOTEK Corp
 1518  PEP MODULAR Computers GmbH
 1519  TELEFON AKTIEBOLAGET LM Ericsson
@@ -4983,7 +5280,7 @@
 		1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem
-		1522 0500  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0500  RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem
 		1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem
 1523  MUSIC Semiconductors
 1524  ENE Technology Inc
@@ -5177,7 +5474,8 @@
 15c4  EVSX Inc
 15c5  Procomp Informatics Ltd
 15c6  Technical University of Budapest
-15c7  Tateyama Dystem Laboratory Co Ltd
+15c7  Tateyama System Laboratory Co Ltd
+	0349  Tateyama C-PCI PLC/NC card Rev.01A
 15c8  Penta Media Co Ltd
 15c9  Serome Technology Inc
 15ca  Bitboys OY
@@ -5211,6 +5509,7 @@
 15e6  Agere Inc
 15e7  Get Engineering Corp
 15e8  National Datacomm Corp
+	0130  Wireless PCI Card
 15e9  Pacific Digital Corp
 15ea  Tokyo Denshi Sekei K.K.
 15eb  Drsearch GmbH
@@ -5250,16 +5549,32 @@
 1629  Kongsberg Spacetec AS
 	1003  Format synchronizer v3.0
 	2002  Fast Universal Data Output
+1638  Standard Microsystems Corp [SMC]
+	1100  SMC2602W EZConnect / Addtron AWA-100
 1657  Brocade Communications Systems, Inc.
+165d  Hsing Tech. Enterprise Co., Ltd.
+1661  Worldspace Corp.
 1668  Action Tec Electronics Inc
+16ec  U.S. Robotics
+	3685  Wireless Access PCI Adapter Model 022415
 16f6  VideoTele.com, Inc.
 170b  NetOctave Inc
 170c  YottaYotta Inc.
-173b  Altima (nee BroadCom)
+173b  Altima (nee Broadcom)
 	03e8  AC1000 Gigabit Ethernet
 	03ea  AC9100 Gigabit Ethernet
 1743  Peppercon AG
 	8139  ROL/F-100 Fast Ethernet Adapter with ROL
+174b  PC Partner Limited
+175e  Sanera Systems, Inc.
+# also used by Struck Innovative Systeme for joint developments
+1796  Research Centre Juelich
+	0001  SIS1100 [Gigabit link]
+	0002  HOTlink
+	0003  Counter Timer
+	0004  CAMAC Controller
+	0005  PROFIBUS
+	0006  AMCC HOTlink
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
@@ -5290,7 +5605,7 @@
 		3388 8011  VXPro II Chipset CPU to PCI Bridge
 	8012  VXPro II Chipset
 		3388 8012  VXPro II Chipset PCI to ISA Bridge
-	8013  VXPro II Chipset
+	8013  VXPro II IDE
 		3388 8013  VXPro II Chipset EIDE Controller
 3411  Quantum Designs (H.K.) Inc
 3513  ARCOM Control Systems Ltd
@@ -5357,11 +5672,29 @@
 		4a14 5000  RT8029-Based Ethernet Adapter
 4b10  Buslogic Inc.
 4c48  LUNG HWA Electronics
+4c53  SBS Technologies
 4ca1  Seanix Technology Inc
 4d51  MediaQ Inc.
 	0200  MQ-200
 4d54  Microtechnica Co Ltd
 4ddc  ILC Data Device Corp
+	0100  DD-42924I5-300 (ARINC 429 Data Bus)
+	0801  BU-65570I1 MIL-STD-1553 Test and Simulation
+	0802  BU-65570I2 MIL-STD-1553 Test and Simulation
+	0811  BU-65572I1 MIL-STD-1553 Test and Simulation
+	0812  BU-65572I2 MIL-STD-1553 Test and Simulation
+	0881  BU-65570T1 MIL-STD-1553 Test and Simulation
+	0882  BU-65570T2 MIL-STD-1553 Test and Simulation
+	0891  BU-65572T1 MIL-STD-1553 Test and Simulation
+	0892  BU-65572T2 MIL-STD-1553 Test and Simulation
+	0901  BU-65565C1 MIL-STD-1553 Data Bus
+	0902  BU-65565C2 MIL-STD-1553 Data Bus
+	0903  BU-65565C3 MIL-STD-1553 Data Bus
+	0904  BU-65565C4 MIL-STD-1553 Data Bus
+	0b01  BU-65569I1 MIL-STD-1553 Data Bus
+	0b02  BU-65569I2 MIL-STD-1553 Data Bus
+	0b03  BU-65569I3 MIL-STD-1553 Data Bus
+	0b04  BU-65569I4 MIL-STD-1553 Data Bus
 5046  GemTek Technology Corporation
 	1001  PCI Radio
 5053  Voyetra Technologies
@@ -5472,12 +5805,27 @@
 	8a26  ProSavage KM133
 	8c00  ViRGE/M3
 	8c01  ViRGE/MX
+		1179 0001  ViRGE/MX
 	8c02  ViRGE/MX+
 	8c03  ViRGE/MX+MV
 	8c10  86C270-294 Savage/MX-MV
 	8c11  82C270-294 Savage/MX
 	8c12  86C270-294 Savage/IX-MV
 	8c13  86C270-294 Savage/IX
+	8c22  SuperSavage MX/128
+	8c24  SuperSavage MX/64
+	8c26  SuperSavage MX/64C
+	8c2a  SuperSavage IX/128 SDR
+	8c2b  SuperSavage IX/128 DDR
+	8c2c  SuperSavage IX/64 SDR
+	8c2d  SuperSavage IX/64 DDR
+	8c2e  SuperSavage IX/C SDR
+		1014 01fc  ThinkPad T23 (2647-4MG)
+	8c2f  SuperSavage IX/C DDR
+# Integrated in VIA ProSavage PN133 North Bridge
+	8d01  VT8603 [ProSavage PN133] AGP4X VGA Controller (Twister)
+	8d02  VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK)
+	8d04  VT8751 [ProSavageDDR P4M266] VGA Controller
 	9102  86C410 Savage 2000
 		1092 5932  Viper II Z200
 		1092 5934  Viper II Z200
@@ -5512,6 +5860,7 @@
 	0011  PWDOG2 [PCI-Watchdog 2]
 8086  Intel Corp.
 	0007  82379AB
+	0008  Extended Express System Support Controller
 	0039  21145
 	0122  82437FX
 	0482  82375EB
@@ -5534,8 +5883,8 @@
 		0e11 004a  NC6136 Gigabit Server Adapter
 		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
 		8086 1003  PRO/1000 F Server Adapter
-	1002  Pro 100 LAN Modem 56 Cardbus II
-		8086 200e  Pro 100 LAN Modem 56 Cardbus II
+	1002  Pro 100 LAN+Modem 56 Cardbus II
+		8086 200e  Pro 100 LAN+Modem 56 Cardbus II
 		8086 2013  Pro 100 SR Mobile Combo Adapter
 		8086 2017  Pro 100 S Combo Mobile Adapter
 	1004  82543GC Gigabit Ethernet Controller
@@ -5552,34 +5901,54 @@
 		8086 1109  PRO/1000 XF Server Adapter
 		8086 2109  PRO/1000 XF Server Adapter
 	100c  82544GC Gigabit Ethernet Controller
-		8086 1109  PRO/1000 T Desktop Adapter
 		8086 1112  PRO/1000 T Desktop Adapter
-		8086 2109  PRO/1000 T Desktop Adapter
 		8086 2112  PRO/1000 T Desktop Adapter
 	100d  82544GC Gigabit Ethernet Controller
+	100e  82540EM Gigabit Ethernet Controller
+		8086 001e  PRO/1000 MT Desktop Adapter
+		8086 002e  PRO/1000 MT Desktop Adapter
+	100f  82545EM Gigabit Ethernet Controller
+		8086 1001  PRO/1000 MT Server Adapter
+	1010  82546EB Gigabit Ethernet Controller
+		8086 1011  PRO/1000 MT Dual Port Server Adapter
+	1011  82545EM Gigabit Ethernet Controller
+		8086 1002  PRO/1000 MF Server Adapter
+	1012  82546EB Gigabit Ethernet Controller
+		8086 1012  PRO/1000 MF Dual Port Server Adapter
 	1029  82559 Ethernet Controller
 	1030  82559 InBusiness 10/100
-	1031  82801CAM (ICH3) Chipset Ethernet Controller
-		1014 0209  EtherExpress PRO/100 VE
-		104d 80e7  Vaio PCG Series
+	1031  82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller
+		1014 0209  ThinkPad A30p (2653-64G)
+		104d 80e7  Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 		107b 5350  EtherExpress PRO/100 VE
 		1179 0001  EtherExpress PRO/100 VE
 		144d c000  EtherExpress PRO/100 VE
 		144d c001  EtherExpress PRO/100 VE
 		144d c003  EtherExpress PRO/100 VE
-	1032  82801CAM (ICH3) Chipset Ethernet Controller
-	1033  82801CAM (ICH3) Chipset Ethernet Controller
-	1034  82801CAM (ICH3) Chipset Ethernet Controller
-	1035  82801CAM (ICH3) Chipset Ethernet Controller
-	1036  82801CAM (ICH3) Chipset Ethernet Controller
+	1032  82801CAM (ICH3) PRO/100 VE Ethernet Controller
+	1033  82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller
+	1034  82801CAM (ICH3) PRO/100 VM Ethernet Controller
+	1035  82801CAM (ICH3)/82562EH (LOM)  Ethernet Controller
+	1036  82801CAM (ICH3) 82562EH Ethernet Controller
 	1037  82801CAM (ICH3) Chipset Ethernet Controller
-	1038  82801CAM (ICH3) Chipset Ethernet Controller
+	1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller
+	1039  82801BD PRO/100 VE (LOM) Ethernet Controller
+	103a  82801BD PRO/100 VE (CNR) Ethernet Controller
+	103b  82801BD PRO/100 VM (LOM) Ethernet Controller
+	103c  82801BD PRO/100 VM (CNR) Ethernet Controller
+	103d  82801BD PRO/100 VE (MOB) Ethernet Controller
+	103e  82801BD PRO/100 VM (MOB) Ethernet Controller
+	1059  82551QM Ethernet Controller
 	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
 	1131  82815 815 Chipset AGP Bridge
 	1132  82815 CGC [Chipset Graphics Controller]
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
 	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
 		8086 1161  82806AA PCI64 Hub APIC
-	1200  Unknown device
+	1200  Intel IXP1200 Network Processor
 		172a 0000  AEP SSL Accelerator
 	1209  82559ER
 	1221  82092AA_0
@@ -5615,6 +5984,7 @@
 		0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)
 		0e11 b1a4  NC7131 Gigabit Server Adapter
 		1014 005c  82558B Ethernet Pro 10/100
+		1014 01bc  82559 Fast Ethernet LAN On Motherboard
 		1014 01f1  10/100 Ethernet Server Adapter
 		1014 01f2  10/100 Ethernet Server Adapter
 		1014 0207  Ethernet Pro/100 S
@@ -5629,6 +5999,9 @@
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
 		1033 801f  PK-UG-X006
+		1033 8026  PK-UG-X006
+		1033 8063  82559-based Fast Ethernet Adapter
+		1033 8064  82559-based Fast Ethernet Adapter
 		103c 10c0  NetServer 10/100TX
 		103c 10c3  NetServer 10/100TX
 		103c 10ca  NetServer 10/100TX
@@ -5637,7 +6010,11 @@
 		103c 10e4  NetServer 10/100TX
 		103c 1200  NetServer 10/100TX
 		10c3 1100  SmartEther100 SC1100
+		10cf 1115  8255x-based Ethernet Adapter (10/100)
+		10cf 1143  8255x-based Ethernet Adapter (10/100)
+		1179 0001  8255x-based Ethernet Adapter (10/100)
 		1179 0002  PCI FastEther LAN on Docker
+		1179 0003  8255x-based Fast Ethernet
 		1259 2560  AT-2560 100
 		1259 2561  AT-2560 100 FX Ethernet Adapter
 		1266 0001  NE10/100 Adapter
@@ -5745,6 +6122,8 @@
 	1250  430HX - 82439HX TXC [Triton II]
 	1360  82806AA PCI64 Hub PCI Bridge
 	1361  82806AA PCI64 Hub Controller (HRes)
+		8086 1361  82806AA PCI64 Hub Controller (HRes)
+		8086 8000  82806AA PCI64 Hub Controller (HRes)
 	1460  82870P2 P64H2 Hub PCI Bridge
 	1461  82870P2 P64H2 I/OxAPIC
 	1462  82870P2 P64H2 Hot Plug Controller
@@ -5781,6 +6160,7 @@
 	2412  82801AA USB
 	2413  82801AA SMBus
 	2415  82801AA AC'97 Audio
+		1028 0095  Precision Workstation 220 Integrated Digital Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
 		11d4 5340  SoundMAX Integrated Digital Audio
@@ -5797,14 +6177,55 @@
 	2428  82801AB PCI Bridge
 	2440  82801BA ISA Bridge (LPC)
 	2442  82801BA/BAM USB (Hub #1)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2443  82801BA/BAM SMBus
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2444  82801BA/BAM USB (Hub #2)
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
 	2445  82801BA/BAM AC'97 Audio
+		104d 80df  Vaio PCG-FX403
+		1462 3370  STAC9721 AC
+		147b 0507  TH7II-RAID
 	2446  82801BA/BAM AC'97 Modem
+		104d 80df  Vaio PCG-FX403
 	2448  82801BAM/CAM PCI Bridge
 	2449  82801BA/BAM/CA/CAM Ethernet Controller
+		0e11 0012  EtherExpress PRO/100 VM
+		0e11 0091  EtherExpress PRO/100 VE
+		1014 01ce  EtherExpress PRO/100 VE
+		1014 01dc  EtherExpress PRO/100 VE
+		1014 01eb  EtherExpress PRO/100 VE
+		1014 01ec  EtherExpress PRO/100 VE
+		1014 0202  EtherExpress PRO/100 VE
+		1014 0205  EtherExpress PRO/100 VE
+		1014 0217  EtherExpress PRO/100 VE
+		1014 0234  EtherExpress PRO/100 VE
+		1014 023d  EtherExpress PRO/100 VE
+		1014 0244  EtherExpress PRO/100 VE
+		1014 0245  EtherExpress PRO/100 VE
+		109f 315d  EtherExpress PRO/100 VE
+		109f 3181  EtherExpress PRO/100 VE
+		1186 7801  EtherExpress PRO/100 VE
+		144d 2602  HomePNA 1M CNR
+		8086 3010  EtherExpress PRO/100 VE
+		8086 3011  EtherExpress PRO/100 VM
+		8086 3012  82562EH based Phoneline
+		8086 3013  EtherExpress PRO/100 VE
+		8086 3014  EtherExpress PRO/100 VM
+		8086 3015  82562EH based Phoneline
+		8086 3016  EtherExpress PRO/100 P Mobile Combo
+		8086 3017  EtherExpress PRO/100 P Mobile
+		8086 3018  EtherExpress PRO/100
 	244a  82801BAM IDE U100
+		1025 1016  Travelmate 612TX
+		104d 80df  Vaio PCG-FX403
 	244b  82801BA IDE U100
+		1043 8027  TUSL2-C Mainboard
+		147b 0507  TH7II-RAID
 	244c  82801BAM ISA Bridge (LPC)
 	244e  82801BA/CA/DB PCI Bridge
 	2450  82801E ISA Bridge (LPC)
@@ -5816,12 +6237,28 @@
 	245e  82801E PCI Bridge
 	2480  82801CA ISA Bridge (LPC)
 	2482  82801CA/CAM USB (Hub #1)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2483  82801CA/CAM SMBus
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2484  82801CA/CAM USB (Hub #2)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2485  82801CA/CAM AC'97 Audio
+		1014 0222  ThinkPad T23 (2647-4MG)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	2486  82801CA/CAM AC'97 Modem
+		1014 0223  ThinkPad A30p (2653-64G)
+		1014 0503  ThinkPad R31 2656BBG
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		134d 4c21  Dell Inspiron 2100 internal modem
 	2487  82801CA/CAM USB (Hub #3)
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248a  82801CAM IDE U100
+		1014 0220  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	248b  82801CA IDE U100
 	248c  82801CAM ISA Bridge (LPC)
 	24c0  82801DB ISA Bridge (LPC)
@@ -5831,9 +6268,10 @@
 	24c5  82801DB AC'97 Audio
 	24c6  82801DB AC'97 Modem
 	24c7  82801DB USB (Hub #3)
-	24cb  82801DB IDE U100
+	24cb  82801DB ICH4 IDE
 	24cd  82801DB USB EHCI Controller
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1028 0095  Precision Workstation 220 Chipset
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
@@ -5842,20 +6280,26 @@
 	2520  82805AA MTH Memory Translator Hub
 	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
-	2531  82850 860 (Wombat) Chipset Host Bridge (MCH)
+		147b 0507  TH7II-RAID
+	2531  82860 860 (Wombat) Chipset Host Bridge (MCH)
 	2532  82850 850 (Tehama) Chipset AGP Bridge
 	2533  82860 860 (Wombat) Chipset AGP Bridge
 	2534  82860 860 (Wombat) Chipset PCI Bridge
-	2540  e7500 (Plumas) DRAM Controller
-	2541  e7500 (Plumas) DRAM Controller Error Reporting
-	2543  e7500 (Plumas) HI_B Virtual PCI-to-PCI Bridge (F0)
-	2544  e7500 (Plumas) HI_B Virtual PCI-to-PCI Bridge (F1)
-	2545  e7500 (Plumas) HI_C Virtual PCI-to-PCI Bridge (F0)
-	2546  e7500 (Plumas) HI_C Virtual PCI-to-PCI Bridge (F1)
-	2547  e7500 (Plumas) HI_D Virtual PCI-to-PCI Bridge (F0)
-	2548  e7500 (Plumas) HI_D Virtual PCI-to-PCI Bridge (F1)
+	2540  e7500 [Plumas] DRAM Controller
+	2541  e7500 [Plumas] DRAM Controller Error Reporting
+	2543  e7500 [Plumas] HI_B Virtual PCI Bridge (F0)
+	2544  e7500 [Plumas] HI_B Virtual PCI Bridge (F1)
+	2545  e7500 [Plumas] HI_C Virtual PCI Bridge (F0)
+	2546  e7500 [Plumas] HI_C Virtual PCI Bridge (F1)
+	2547  e7500 [Plumas] HI_D Virtual PCI Bridge (F0)
+	2548  e7500 [Plumas] HI_D Virtual PCI Bridge (F1)
+	2560  82845G/GL [Brookdale-G] Chipset Host Bridge
+	2561  82845G/GL [Brookdale-G] Chipset AGP Bridge
+	2562  82845G/GL [Brookdale-G] Chipset Integrated Graphics Device
 	3092  Integrated RAID
 	3575  82830 830 Chipset Host Bridge
+		1014 021d  ThinkPad T23 (2647-4MG) or A30p (2653-64G)
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
 	3576  82830 830 Chipset AGP Bridge
 	3577  82830 CGC [Chipset Graphics Controller]
 	3578  82830 830 Chipset Host Bridge
@@ -5902,10 +6346,10 @@
 	71a0  440GX - 82443GX Host bridge
 	71a1  440GX - 82443GX AGP bridge
 	71a2  440GX - 82443GX Host bridge (AGP disabled)
-	7600  82372FB PCI to ISA Bridge
-	7601  82372FB PIIX4 IDE
-	7602  82372FB [PCI-to-USB UHCI]
-	7603  82372FB System Management Bus Controller
+	7600  82372FB PIIX5 ISA
+	7601  82372FB PIIX5 IDE
+	7602  82372FB PIIX5 USB
+	7603  82372FB PIIX5 SMBus
 	7800  i740
 		003d 0008  Starfighter AGP
 		003d 000b  Starfighter AGP
@@ -5920,14 +6364,20 @@
 	84cb  450NX - 82454NX/84460GX PCI Expander Bridge
 	84e0  460GX - 84460GX System Address Controller (SAC)
 	84e1  460GX - 84460GX System Data Controller (SDC)
-	84e2  460GX - 84460GX AGP Bridge (GXB)
+	84e2  460GX - 84460GX AGP Bridge (GXB function 2)
 	84e3  460GX - 84460GX Memory Address Controller (MAC)
 	84e4  460GX - 84460GX Memory Data Controller (MDC)
 	84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)
+	84ea  460GX - 84460GX AGP Bridge (GXB function 1)
 	9621  Integrated RAID
 	9622  Integrated RAID
 	9641  Integrated RAID
 	96a1  Integrated RAID
+	b152  21152 PCI-to-PCI Bridge
+# observed, and documented in Intel revision note; new mask of 1011:0026
+	b154  21154 PCI-to-PCI Bridge
+	b555  21555 Non transparent PCI-to-PCI Bridge
+		e4bf 1000  CC8-1-BLUES
 	ffff  450NX/GX [Orion] - 82453KX/GX Memory controller [BUG]
 8800  Trigem Computer Inc.
 	2008  Video assistent component
@@ -5955,6 +6405,7 @@
 	5478  AIC-7850
 	5575  AVA-2930
 	5578  AIC-7855
+	5647  ANA-7711 TCP Offload Engine
 	5675  AIC-755x
 	5678  AIC-7856
 	5775  AIC-755x
@@ -6079,6 +6530,8 @@
 	00c3  AIC-7899D U160/m
 	00c5  RAID subsystem HBA
 	00cf  AIC-7899P U160/m
+	0285  AAC-RAID
+		1028 0287  PowerEdge Expandable RAID Controller 320/DC
 907f  Atronics
 	2015  IDE-2015PL
 919a  Gigapixel Corp
@@ -6088,7 +6541,7 @@
 	6565  6565
 9710  NetMos Technology
 	9815  VScom 021H-EP2 2 port parallel adaptor
-	9835  2xserial 1xparallel port adapter
+	9835  222N-2 I/O Card (2S+1P)
 a0a0  AOPEN Inc.
 a0f1  UNISYS Corporation
 a200  NEC Corporation
@@ -6117,10 +6570,24 @@
 	0001  Model 300 128k
 		0059 0001  128k ISDN-S/T Adapter
 		0059 0003  128k ISDN-U Adapter
+	0002  Tiger100APC ISDN chipset
 e4bf  EKF Elektronik GmbH
 ea01  Eagle Technology
 eabb  Aashima Technology B.V.
 eace  Endace Measurement Systems, Ltd
+	3100  DAG 3.10 OC-3/OC-12
+	3200  DAG 3.2x OC-3/OC-12
+	320e  DAG 3.2E Fast Ethernet
+	340e  DAG 3.4E Fast Ethernet
+	341e  DAG 3.41E Fast Ethernet
+	3500  DAG 3.5 OC-3/OC-12
+	351c  DAG 3.5ECM Fast Ethernet
+	4100  DAG 4.10 OC-48
+	4110  DAG 4.11 OC-48
+	4220  DAG 4.2 OC-48
+	422e  DAG 4.2E Dual Gigabit Ethernet
+ec80  Belkin Corporation
+	ec00  F5D6000
 ecc0  Echo Corporation
 edd8  ARK Logic Inc
 	a091  1000PV [Stingray]
@@ -6266,6 +6733,7 @@
 	03  USB Controller
 		00  UHCI
 		10  OHCI
+		20  EHCI
 		80  Unspecified
 		fe  USB Device
 	04  Fibre Channel
diff -urN linux-2.4.20-pre2/drivers/pnp/isapnp.c linux-2.4.20-pre3/drivers/pnp/isapnp.c
--- linux-2.4.20-pre2/drivers/pnp/isapnp.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/pnp/isapnp.c	Sat Aug 17 14:18:52 2002
@@ -28,6 +28,8 @@
  *  2001-11-07  Added isapnp_{,un}register_driver calls along the lines
  *              of the pci driver interface
  *              Kai Germaschewski <kai.germaschewski@gmx.de>
+ *  2002-06-06  Made the use of dma channel 0 configurable 
+ *              Gerald Teschl <gerald.teschl@univie.ac.at>
  */
 
 #include <linux/config.h>
@@ -59,6 +61,7 @@
 int isapnp_disable;			/* Disable ISA PnP */
 int isapnp_rdp;				/* Read Data Port */
 int isapnp_reset = 1;			/* reset all PnP cards (deactivate) */
+int isapnp_allow_dma0 = -1;		/* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */
 int isapnp_skip_pci_scan;		/* skip PCI resource scanning */
 int isapnp_verbose = 1;			/* verbose mode */
 int isapnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
@@ -74,6 +77,8 @@
 MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
 MODULE_PARM(isapnp_reset, "i");
 MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
+MODULE_PARM(isapnp_allow_dma0, "i");
+MODULE_PARM_DESC(isapnp_allow_dma0, "Allow dma value 0 during auto activation");
 MODULE_PARM(isapnp_skip_pci_scan, "i");
 MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning");
 MODULE_PARM(isapnp_verbose, "i");
@@ -1750,13 +1755,14 @@
 
 static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
 {
-	int i;
+	int i, mindma =1;
 	struct pci_dev *dev;
 
 	/* Some machines allow DMA 0, but others don't. In fact on some 
 	   boxes DMA 0 is the memory refresh. Play safe */
-	   
-	if (dma < 1 || dma == 4 || dma > 7)
+	if (isapnp_allow_dma0 == 1)
+		mindma = 0;
+	if (dma < mindma || dma == 4 || dma > 7)
 		return 1;
 	for (i = 0; i < 8; i++) {
 		if (isapnp_reserve_dma[i] == dma)
diff -urN linux-2.4.20-pre2/drivers/pnp/isapnp_proc.c linux-2.4.20-pre3/drivers/pnp/isapnp_proc.c
--- linux-2.4.20-pre2/drivers/pnp/isapnp_proc.c	Wed Jan 17 13:29:14 2001
+++ linux-2.4.20-pre3/drivers/pnp/isapnp_proc.c	Sat Aug 17 14:18:52 2002
@@ -944,6 +944,22 @@
 	res->start = res->end = dma;
 	res->flags = IORESOURCE_DMA;
 }
+
+extern int isapnp_allow_dma0;
+static int isapnp_set_allow_dma0(char *line)
+{
+	int i;
+	char value[32];
+
+	isapnp_get_str(value, line, sizeof(value));
+	i = simple_strtoul(value, NULL, 0);
+	if (i < 0 || i > 1) {
+		printk("isapnp: wrong value %i for allow_dma0\n", i);
+		return 1;
+	}
+	isapnp_allow_dma0 = i;
+	return 0;
+}
  
 static int isapnp_set_dma(char *line)
 {
@@ -1030,6 +1046,8 @@
 	char cmd[32];
 
 	line = isapnp_get_str(cmd, line, sizeof(cmd));
+	if (!strcmp(cmd, "allow_dma0"))
+		return isapnp_set_allow_dma0(line);
 	if (!strcmp(cmd, "card"))
 		return isapnp_set_card(line);
 	if (!strcmp(cmd, "csn"))
diff -urN linux-2.4.20-pre2/drivers/sbus/char/aurora.c linux-2.4.20-pre3/drivers/sbus/char/aurora.c
--- linux-2.4.20-pre2/drivers/sbus/char/aurora.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre3/drivers/sbus/char/aurora.c	Sat Aug 17 14:18:53 2002
@@ -136,25 +136,25 @@
  */
 
 /* Get board number from pointer */
-extern inline int board_No (struct Aurora_board const * bp)
+static inline int board_No (struct Aurora_board const * bp)
 {
 	return bp - aurora_board;
 }
 
 /* Get port number from pointer */
-extern inline int port_No (struct Aurora_port const * port)
+static inline int port_No (struct Aurora_port const * port)
 {
 	return AURORA_PORT(port - aurora_port); 
 }
 
 /* Get pointer to board from pointer to port */
-extern inline struct Aurora_board * port_Board(struct Aurora_port const * port)
+static inline struct Aurora_board * port_Board(struct Aurora_port const * port)
 {
 	return &aurora_board[AURORA_BOARD(port - aurora_port)];
 }
 
 /* Wait for Channel Command Register ready */
-extern inline void aurora_wait_CCR(struct aurora_reg128 * r)
+static inline void aurora_wait_CCR(struct aurora_reg128 * r)
 {
 	unsigned long delay;
 
@@ -173,7 +173,7 @@
  */
 
 /* Must be called with enabled interrupts */
-extern inline void aurora_long_delay(unsigned long delay)
+static inline void aurora_long_delay(unsigned long delay)
 {
 	unsigned long i;
 
@@ -432,7 +432,7 @@
 	sbus_iounmap((unsigned long)bp->r3, 4);
 }
 
-extern inline void aurora_mark_event(struct Aurora_port * port, int event)
+static inline void aurora_mark_event(struct Aurora_port * port, int event)
 {
 #ifdef AURORA_DEBUG
 	printk("aurora_mark_event: start\n");
diff -urN linux-2.4.20-pre2/drivers/sbus/dvma.c linux-2.4.20-pre3/drivers/sbus/dvma.c
--- linux-2.4.20-pre2/drivers/sbus/dvma.c	Fri Feb  9 11:37:03 2001
+++ linux-2.4.20-pre3/drivers/sbus/dvma.c	Sat Aug 17 14:18:53 2002
@@ -18,7 +18,7 @@
 struct sbus_dma *dma_chain;
 
 /* Print out the current values in the DMA control registers */
-extern __inline__ void dump_dma_regs(unsigned long dregs)
+static inline void dump_dma_regs(unsigned long dregs)
 {
 	printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n",
 	       sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR),
diff -urN linux-2.4.20-pre2/drivers/scsi/ChangeLog.ips linux-2.4.20-pre3/drivers/scsi/ChangeLog.ips
--- linux-2.4.20-pre2/drivers/scsi/ChangeLog.ips	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/ChangeLog.ips	Sat Aug 17 14:18:53 2002
@@ -1,6 +1,10 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+        5.00.01  - Sarasota ( 5i ) adapters must always be scanned first  
+                 - Get rid on IOCTL_NEW_COMMAND code  
+                 - Add Extended DCDB Commands for Tape Support in 5I                  
+        
         4.90.11  - Don't actually RESET unless it's physically required
                  - Remove unused compile options
         
@@ -116,4 +120,3 @@
                 - Fixed read/write errors when the adapter is using an
                   8K stripe size.
 
-
\ No newline at end of file
diff -urN linux-2.4.20-pre2/drivers/scsi/Config.in linux-2.4.20-pre3/drivers/scsi/Config.in
--- linux-2.4.20-pre2/drivers/scsi/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/Config.in	Sat Aug 17 14:18:53 2002
@@ -150,7 +150,10 @@
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
    dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
    dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+   if [ "$CONFIG_PARISC" = "y" ]; then
+      dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_GSC $CONFIG_SCSI
+   fi
+   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_ZALON" = "y" -o "$CONFIG_SCSI_ZALON" = "m" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
       int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
       int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
       int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
diff -urN linux-2.4.20-pre2/drivers/scsi/Makefile linux-2.4.20-pre3/drivers/scsi/Makefile
--- linux-2.4.20-pre2/drivers/scsi/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/Makefile	Sat Aug 17 14:18:53 2002
@@ -118,6 +118,7 @@
 obj-$(CONFIG_SCSI_PLUTO)	+= pluto.o
 obj-$(CONFIG_SCSI_DECNCR)	+= NCR53C9x.o	dec_esp.o
 obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx_mod.o
 obj-$(CONFIG_SCSI_PPA)		+= ppa.o
 obj-$(CONFIG_SCSI_IMM)		+= imm.o
 obj-$(CONFIG_JAZZ_ESP)		+= NCR53C9x.o	jazz_esp.o
@@ -136,7 +137,8 @@
 obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
-list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o
+list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o \
+			zalon7xx_mod.o
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o \
 			scsicam.o scsi_proc.o scsi_error.o \
 			scsi_obsolete.o scsi_queue.o scsi_lib.o \
@@ -146,6 +148,7 @@
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 initio-objs	:= ini9100u.o i91uscsi.o
 a100u2w-objs	:= inia100.o i60uscsi.o
+zalon7xx_mod-objs := zalon7xx.o ncr53c8xx.o
 cpqfc-objs	:= cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
 		   cpqfcTSworker.o cpqfcTStrigger.o
 
@@ -167,6 +170,9 @@
 a100u2w.o: $(a100u2w-objs)
 	$(LD) -r -o $@ $(a100u2w-objs)
 
+zalon7xx_mod.o: $(zalon7xx_mod-objs)
+	$(LD) -r -o $@ $(zalon7xx_mod-objs)
+
 cpqfc.o: $(cpqfc-objs)
 	$(LD) -r -o $@ $(cpqfc-objs)
 
@@ -183,7 +189,7 @@
 
 53c7xx_d.h: 53c7xx.scr script_asm.pl
 	ln -sf 53c7xx.scr fake7.c
-	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family
+	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710
 	mv script.h 53c7xx_d.h
 	mv scriptu.h 53c7xx_u.h
 	rm fake7.c
@@ -194,7 +200,7 @@
 
 sim710_d.h: sim710.scr script_asm.pl
 	ln -sf sim710.scr fake7.c
-	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family
+	$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710
 	mv script.h sim710_d.h
 	mv scriptu.h sim710_u.h
 	rm fake7.c
diff -urN linux-2.4.20-pre2/drivers/scsi/NCR53C9x.c linux-2.4.20-pre3/drivers/scsi/NCR53C9x.c
--- linux-2.4.20-pre2/drivers/scsi/NCR53C9x.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/NCR53C9x.c	Sat Aug 17 14:18:53 2002
@@ -289,7 +289,7 @@
 #endif
 
 #ifdef DEBUG_ESP_CMDS
-extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
 			   unchar cmd)
 {
 	esp->espcmdlog[esp->espcmdent] = cmd;
diff -urN linux-2.4.20-pre2/drivers/scsi/cpqfcTSinit.c linux-2.4.20-pre3/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.20-pre2/drivers/scsi/cpqfcTSinit.c	Thu Oct 25 13:53:50 2001
+++ linux-2.4.20-pre3/drivers/scsi/cpqfcTSinit.c	Sat Aug 17 14:18:53 2002
@@ -261,10 +261,22 @@
 /* "Entry" point to discover if any supported PCI 
    bus adapter can be found
 */
-// We're supporting:
-// Compaq 64-bit, 66MHz HBA with Tachyon TS
-// Agilent XL2 
-#define HBA_TYPES 2
+/* We're supporting:
+ * Compaq 64-bit, 66MHz HBA with Tachyon TS
+ * Agilent XL2 
+ * HP Tachyon
+ */
+#define HBA_TYPES 3
+
+#ifndef PCI_DEVICE_ID_COMPAQ_
+#define PCI_DEVICE_ID_COMPAQ_TACHYON	0xa0fc
+#endif
+
+static struct SupportedPCIcards cpqfc_boards[] __initdata = {
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
+};
 
 
 int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
@@ -274,35 +286,28 @@
   struct Scsi_Host *HostAdapter = NULL;
   CPQFCHBA *cpqfcHBAdata = NULL; 
   struct timer_list *cpqfcTStimer = NULL;
-  SupportedPCIcards PCIids[HBA_TYPES];
   int i;
-  
+
   ENTER("cpqfcTS_detect");
-  
+
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
   ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
 #else
   ScsiHostTemplate->proc_name = "cpqfcTS";
 #endif
-  
+
   if( pci_present() == 0) // no PCI busses?
   {
     printk( "  no PCI bus?@#!\n");
     return NumberOfAdapters;
   }
 
-  // what HBA adapters are we supporting?
-  PCIids[0].vendor_id = PCI_VENDOR_ID_COMPAQ;
-  PCIids[0].device_id = CPQ_DEVICE_ID;
-  PCIids[1].vendor_id = PCI_VENDOR_ID_HP; // i.e. 103Ch (Agilent == HP for now)
-  PCIids[1].device_id = AGILENT_XL2_ID;   // i.e. 1029h
-
   for( i=0; i < HBA_TYPES; i++)
   {
     // look for all HBAs of each type
 
-    while( (PciDev =
-      pci_find_device( PCIids[i].vendor_id, PCIids[i].device_id, PciDev) ))
+    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
+				    cpqfc_boards[i].device_id, PciDev)))
     {
 
       if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
diff -urN linux-2.4.20-pre2/drivers/scsi/cpqfcTSstructs.h linux-2.4.20-pre3/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.20-pre2/drivers/scsi/cpqfcTSstructs.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/cpqfcTSstructs.h	Sat Aug 17 14:18:53 2002
@@ -95,14 +95,11 @@
 
 #define DEV_NAME "cpqfcTS"
 
-#define CPQ_DEVICE_ID     0xA0FC
-#define AGILENT_XL2_ID    0x1029
-
-typedef struct
+struct SupportedPCIcards
 {
   __u16 vendor_id;
   __u16 device_id;
-} SupportedPCIcards;
+};
 			 
 // nn:nn denotes bit field
                             // TachyonHeader struct def.
diff -urN linux-2.4.20-pre2/drivers/scsi/cpqfcTSworker.c linux-2.4.20-pre3/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.20-pre2/drivers/scsi/cpqfcTSworker.c	Thu Oct 25 13:53:50 2001
+++ linux-2.4.20-pre3/drivers/scsi/cpqfcTSworker.c	Sat Aug 17 14:18:53 2002
@@ -2911,7 +2911,7 @@
     }
   }
 
-Done:  
+Done:  ;
 }
 
 static void 
@@ -3028,7 +3028,7 @@
 
 
 
-Done:
+Done: ;
 
 }
 
diff -urN linux-2.4.20-pre2/drivers/scsi/dpt_i2o.c linux-2.4.20-pre3/drivers/scsi/dpt_i2o.c
--- linux-2.4.20-pre2/drivers/scsi/dpt_i2o.c	Sat Aug 17 14:18:21 2002
+++ linux-2.4.20-pre3/drivers/scsi/dpt_i2o.c	Sat Aug 17 14:18:53 2002
@@ -110,10 +110,6 @@
 static adpt_hba* hba_chain = NULL;
 static int hba_count = 0;
 
-// Debug flags to be put into the HBA flags field when initialized
-// Make sure to enable DEBUG_PRINT for these flags to work
-static unsigned long DebugFlags = HBA_FLAGS_DBG_SCAN_B | HBA_FLAGS_DBG_FLAGS_MASK;
-
 static struct file_operations adpt_fops = {
 	ioctl: adpt_ioctl,
 	open: adpt_open,
@@ -1141,7 +1137,8 @@
        // to support async LCT get
 	wait_data->next = adpt_post_wait_queue;
 	adpt_post_wait_queue = wait_data;
-	adpt_post_wait_id = (++adpt_post_wait_id & 0x7fff);
+	adpt_post_wait_id++;
+	adpt_post_wait_id = (adpt_post_wait_id & 0x7fff);
 	wait_data->id =  adpt_post_wait_id;
 	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
 
diff -urN linux-2.4.20-pre2/drivers/scsi/esp.c linux-2.4.20-pre3/drivers/scsi/esp.c
--- linux-2.4.20-pre2/drivers/scsi/esp.c	Sun Feb 18 19:49:55 2001
+++ linux-2.4.20-pre3/drivers/scsi/esp.c	Sat Aug 17 14:18:54 2002
@@ -378,7 +378,7 @@
 #endif
 
 #ifdef DEBUG_ESP_CMDS
-extern inline void esp_cmd(struct esp *esp, u8 cmd)
+static inline void esp_cmd(struct esp *esp, u8 cmd)
 {
 	esp->espcmdlog[esp->espcmdent] = cmd;
 	esp->espcmdent = (esp->espcmdent + 1) & 31;
diff -urN linux-2.4.20-pre2/drivers/scsi/ips.c linux-2.4.20-pre3/drivers/scsi/ips.c
--- linux-2.4.20-pre2/drivers/scsi/ips.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/ips.c	Sat Aug 17 14:18:54 2002
@@ -2,6 +2,8 @@
 /* ips.c -- driver for the IBM ServeRAID controller                          */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 2000 IBM Corporation                                        */
 /*                                                                           */
@@ -40,7 +42,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
-/*      ipslinux@us.ibm.com          	                                      */
+/*      ipslinux@adaptec.com     	                                         */
 /*                                                                           */
 /* For system support issues, contact your local IBM Customer support.       */
 /* Directions to find IBM Customer Support for each country can be found at: */
@@ -121,6 +123,9 @@
 /* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */
 /* 4.90.11  - Don't actually RESET unless it's physically required           */
 /*          - Remove unused compile options                                  */
+/* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
+/*          - Get rid on IOCTL_NEW_COMMAND code                              */
+/*          - Add Extended DCDB Commands for Tape Support in 5I              */
 /*****************************************************************************/
 
 /*
@@ -193,8 +198,9 @@
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "4.90"
-#define IPS_VERSION_LOW         ".18 "
+#define IPS_VERSION_HIGH        "5.10"
+#define IPS_VERSION_LOW         ".21 "
+
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 struct proc_dir_entry proc_scsi_ips = {
@@ -262,17 +268,32 @@
 static int          ips_cd_boot = 0;                 /* Booting from ServeRAID Manager CD */
 static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
 static int          ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
+static uint32_t     MaxLiteCmds = 32;                /* Max Active Cmds for a Lite Adapter */  
 
 IPS_DEFINE_COMPAT_TABLE( Compatable );               /* Version Compatability Table      */
 
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+   /* This table describes any / all ServeRAID Adapters */
    static struct  pci_device_id  ips_pci_table[]  __devinitdata = {
-           { 0x1014, 0x002E, PCI_ANY_ID,PCI_ANY_ID, 0, 0, 0 },
-           { 0x1014, 0x01BD, PCI_ANY_ID,PCI_ANY_ID, 0, 0, 0 },
+           { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+           { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
            { 0, }
    };
 
+   /* This table describes only Sarasota ( ServeRAID 5i ) Adapters */
+   static struct  pci_device_id  ips_pci_table_5i[]  __devinitdata = {
+                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x259, 0, 0 },
+                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x258, 0, 0 },
+                   { 0, }
+                   };   
+    
+   /* This table describes all i960 Adapters */
+   static struct  pci_device_id  ips_pci_table_i960[]  __devinitdata = {
+                   { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+                   { 0, }
+                   };   
+
    MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
    static char ips_hot_plug_name[] = "ips";
@@ -284,8 +305,23 @@
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table,
        probe:		ips_insert_device,
-       remove:		__devexit_p(ips_remove_device),
+       remove:		ips_remove_device,
+   }; 
+           
+   struct pci_driver ips_pci_driver_5i = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_5i,
+       probe:		ips_insert_device,
+       remove:		ips_remove_device,
+   };
+
+   struct pci_driver ips_pci_driver_i960 = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_i960,
+       probe:		ips_insert_device,
+       remove:		ips_remove_device,
    };
+
 #endif
 
 /*
@@ -307,8 +343,8 @@
    "ServeRAID 4L",
    "ServeRAID 4Mx",
    "ServeRAID 4Lx",
-   "ServeRAID 5I",
-   "ServeRAID 5I"
+   "ServeRAID 5i",
+   "ServeRAID 5i"
 };
 
 static struct notifier_block ips_notifier = {
@@ -322,7 +358,7 @@
 IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_UNK,
 IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,
+IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
 IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
 IPS_DATA_NONE, IPS_DATA_UNK,  IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_IN,
@@ -385,7 +421,6 @@
 void do_ipsintr(int, void *, struct pt_regs *);
 static int ips_hainit(ips_ha_t *);
 static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
-static int ips_send(ips_ha_t *, ips_scb_t *, ips_scb_callback);
 static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
 static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
 static int ips_online(ips_ha_t *, ips_scb_t *);
@@ -424,13 +459,10 @@
 static int ips_erase_bios_memio(ips_ha_t *);
 static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
 static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
-static void ips_flash_bios_section(void *);
-static void ips_flash_bios_segment(void *);
 static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_free_flash_copperhead(ips_ha_t *ha);
-static void ips_scheduled_flash_bios(void *);
 static void ips_get_bios_version(ips_ha_t *, int);
 static void ips_identify_controller(ips_ha_t *);
 static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
@@ -472,7 +504,6 @@
 static int ips_is_passthru(Scsi_Cmnd *);
 static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
 static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
-static int ips_newusrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
 
 int  ips_proc_info(char *, char **, off_t, int, int, int);
@@ -516,6 +547,7 @@
       {"nommap", &ips_force_memio, 0},
       {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
       {"cdboot", &ips_cd_boot, 0},
+      {"maxcmds", &MaxLiteCmds, 32},
    };
     
    /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
@@ -543,7 +575,6 @@
    }
 
    return (1);
-}
 
 #else
 
@@ -578,10 +609,14 @@
          }
       }
    }
-}
 
 #endif
 
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+__setup("ips=", ips_setup);
+#endif
 
 /****************************************************************************/
 /*                                                                          */
@@ -622,6 +657,7 @@
    uint32_t          maskbar;
    uint8_t           barnum;
 #endif
+   uint32_t          IsDead;
 
    METHOD_TRACE("ips_detect", 1);
 
@@ -706,12 +742,23 @@
 /**********************************************************************************/
 /* For Kernel Versions 2.4 or greater, use new PCI ( Hot Pluggable ) architecture */
 /**********************************************************************************/
+
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
    spin_unlock_irq(&io_request_lock);
-   pci_module_init(&ips_pci_driver);
+
+   /* By definition, a Sarasota ( 5i ) Adapter MUST be enumerated first or the */
+   /* server may not boot properly. The adapters must be enumerated in exactly */
+   /* the same order as ServeRAID BIOS for the machine to come up properly.    */
+
+   pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters First  */
+   if (ips_num_controllers)                      /* If there is a 5i Adapter   */
+      pci_module_init(&ips_pci_driver_i960);     /*    Get all i960's next     */
+   pci_module_init(&ips_pci_driver);             /* Get all remaining Adapters */
+                                                 /*  ( in normal BUS order )   */
    spin_lock_irq(&io_request_lock);
    if (ips_num_controllers > 0) 
       register_reboot_notifier(&ips_notifier);
+
    return (ips_num_controllers);
 #endif
 
@@ -1111,6 +1158,14 @@
             else
                ha->func.issue = ips_issue_copperhead;
          }
+            
+         /* If Morpheus appears dead, reset it */
+         if ( IPS_IS_MORPHEUS( ha ) ) {
+             IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
+             if ( IsDead == 0xDEADBEEF ) {
+                 ips_reset_morpheus( ha );
+             }
+         }
 
          /*
           * Initialize the card if it isn't already
@@ -1639,10 +1694,6 @@
 
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-__setup("ips=", ips_setup);
-#endif
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_queue                                                  */
@@ -1717,21 +1768,7 @@
    if (ips_is_passthru(SC)) {
 
       ips_copp_wait_item_t *scratch;
-
-      /* The IPS_IOCTL_NEW_COMMAND is only used to flash an adapter.  This should */
-      /* never happen when the adapter is active.  Just in case, check here, and  */
-      /* reject the command if anything else is going on.                         */
-      if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-         if (ha->scb_activelist.count != 0) {
-            /* printk( KERN_WARNING "New IOCTL Cmd Return BUSY: %d Cmds Active\n", */
-            /*                       ha->scb_activelist.count );                   */
-            SC->result = DID_BUS_BUSY << 16;
-            done(SC);
-
-            return (0);
-         }
-      }
-
+      
       /* A Reset IOCTL is only sent by the ServeRAID boot CD in extreme cases. */
       /* There can never be any system activity ( network or disk ), but check */
       /* anyway just as a good practice.                                       */
@@ -1770,6 +1807,9 @@
    else
       ips_putq_wait_tail(&ha->scb_waitlist, SC);
 
+   if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
+         mod_timer(&SC->eh_timeout, jiffies + 120 * HZ);
+
    IPS_HA_LOCK(cpu_flags);
    if ((!test_bit(IPS_IN_INTR, &ha->flags)) &&
        (!test_bit(IPS_IN_ABORT, &ha->flags)) &&
@@ -1779,43 +1819,7 @@
    } else {
       IPS_HA_UNLOCK(cpu_flags);
    }
-
-   /*
-    * If this request was a new style IOCTL wait
-    * for it to finish.
-    *
-    * NOTE: we relinquished the lock above so this should
-    * not cause contention problems
-    */
-   if (ips_is_passthru(SC) && SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-      char      *user_area;
-      char      *kern_area;
-      uint32_t  datasize;
-
-      /* free io_request_lock */
-      spin_unlock_irq(&io_request_lock);
-
-      /* wait for the command to finish */
-      down(&ha->ioctl_sem);
-
-      /* command finished -- copy back */
-      user_area = *((char **) &SC->cmnd[4]);
-      kern_area = ha->ioctl_data;
-      datasize = *((uint32_t *) &SC->cmnd[8]);
-
-      if (datasize) {
-         if (copy_to_user(user_area, kern_area, datasize) > 0) {
-            DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
-                      ips_name, ha->host_num);
-            SC->result = DID_ERROR << 16;
-         }
-      }
-
-      /* reobtain the lock */
-      spin_lock_irq(&io_request_lock);
-      SC->scsi_done(SC);
-   }
-
+   
    /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
    if ( ips_FlashData == ha->ioctl_data ) {                               
       ha->ioctl_data = ha->flash_data;                           
@@ -2214,7 +2218,7 @@
    if (!SC)
       return (0);
 
-   if (((SC->cmnd[0] == IPS_IOCTL_COMMAND) || (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND)) &&
+   if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
        (SC->channel == 0) &&
        (SC->target == IPS_ADAPTER_ID) &&
        (SC->lun == 0) &&
@@ -2361,314 +2365,13 @@
          if(ha->device_id == IPS_DEVICEID_COPPERHEAD &&
             pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)
             return ips_flash_copperhead(ha, pt, scb);
-         if (ips_usrcmd(ha, pt, scb))
-            return (IPS_SUCCESS);
-         else
-            return (IPS_FAILURE);
-      } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-
-         if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
-            /* wrong size */
-            DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
-                      ips_name, ha->host_num);
-
-            SC->result = DID_ERROR << 16;
-
-            return (IPS_FAILURE);
-         }
-
-         /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
-         /* avoid allocating a huge buffer per adapter ( which can fail ). */
-         if ( (ips_FlashData) &&                                            
-              (pt->CmdBSize == IPS_IMAGE_SIZE) &&                                   
-              (ips_FlashDataInUse == 0) ) {                                 
-            ips_FlashDataInUse = 1;                                         
-            ha->flash_data  = ha->ioctl_data;
-            ha->flash_order = ha->ioctl_order;
-            ha->flash_datasize = ha->ioctl_datasize;
-            ha->ioctl_data  = ips_FlashData;                                
-            ha->ioctl_order = 7;                                            
-            ha->ioctl_datasize = IPS_IMAGE_SIZE;                                    
-         }  
-
-         /*
-          * IPSSEND flashing BIOS
-          */
-         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashfw.type == 1) &&
-             (pt->CoppCP.cmd.flashfw.direction == 2) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            struct tq_struct  task;
-            IPS_FLASH_DATA    flash_data;
-
-            /* We only support one packet */
-            if (pt->CoppCP.cmd.flashfw.total_packets != 1) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* copy in the size/buffer ptr from the scsi command */
-            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
-            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
-
-            if (pt->CmdBSize > le32_to_cpu(pt->CoppCP.cmd.flashfw.count)) {
-               pt->CmdBSize = le32_to_cpu(pt->CoppCP.cmd.flashfw.count);
-            } else {
-               /* ERROR: Command/Buffer mismatch */
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      if ((!ha->func.programbios) ||
-          (!ha->func.erasebios) ||
-                (!ha->func.verifybios)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
 
-            /* must have a buffer */
-            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* make sure buffer is big enough */
-            if (pt->CmdBSize > ha->ioctl_datasize) {
-               void *bigger_struct;
-               uint32_t count;
-               uint32_t order;
-
-               /* try to allocate a bigger struct */
-               for (count = PAGE_SIZE, order = 0;
-                    count < pt->CmdBSize;
-                    order++, count <<= 1);
-
-               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-               if (bigger_struct) {
-                  /* free the old memory */
-                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-                  /* use the new memory */
-                  ha->ioctl_data = (char *) bigger_struct;
-                  ha->ioctl_order = order;
-                  ha->ioctl_datasize = count;
-               } else {
-                  pt->BasicStatus = 0x0B;
-                  pt->ExtendedStatus = 0x00;
-                  SC->result = DID_ERROR << 16;
-
-                  spin_unlock(&ha->ips_lock);
-
-                  return (IPS_FAILURE);
-               }
-            }
-
-            /* copy in the buffer */
-            if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-               DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
-                         ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            flash_data.userbuffer = pt->CmdBuffer;
-            flash_data.usersize = pt->CmdBSize;
-            flash_data.kernbuffer = ha->ioctl_data;
-            flash_data.kernsize = ha->ioctl_datasize;
-            flash_data.offset = 0;
-            flash_data.SC = (void *) SC;
-            flash_data.pt = (void *) pt;
-            flash_data.ha = (void *) ha;
-            sema_init( &ha->flash_ioctl_sem, 0 );
-            flash_data.sem = &ha->flash_ioctl_sem;
-
-            task.sync = 0;
-            task.routine = ips_scheduled_flash_bios;
-            task.data = (void *) &flash_data;
-
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
-
-            queue_task(&task, &tq_immediate);
-            mark_bh(IMMEDIATE_BH);
-            
-            /* Wait for the flash to complete */
-            down(&ha->flash_ioctl_sem);
-
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
-
-            return (flash_data.retcode);
-         }
-
-         /*
-          * IPSSEND flashing BIOS in sectioned mode
-          */
-         if ((pt->CoppCP.cmd.flashbios.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashbios.type == 1) &&
-             (pt->CoppCP.cmd.flashbios.direction == 4) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            struct tq_struct  task;
-            IPS_FLASH_DATA    flash_data;
-
-            /* copy in the size/buffer ptr from the scsi command */
-            memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
-            memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
-
-            if (pt->CmdBSize > le32_to_cpu(pt->CoppCP.cmd.flashbios.count)) {
-               pt->CmdBSize = le32_to_cpu(pt->CoppCP.cmd.flashbios.count);
-            } else {
-               /* ERROR: Command/Buffer mismatch */
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            /* Update the Card BIOS */
-            if ((!ha->func.programbios) ||
-                (!ha->func.erasebios) ||
-                (!ha->func.verifybios)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      /* must have a buffer */
-            if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      /* make sure buffer is big enough */
-      if (pt->CmdBSize > ha->ioctl_datasize) {
-         void *bigger_struct;
-               uint32_t count;
-               uint32_t order;
-
-         /* try to allocate a bigger struct */
-               for (count = PAGE_SIZE, order = 0;
-                    count < pt->CmdBSize;
-                    order++, count <<= 1);
-
-               bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-         if (bigger_struct) {
-            /* free the old memory */
-                  free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-            /* use the new memory */
-                  ha->ioctl_data = (char *) bigger_struct;
-                  ha->ioctl_order = order;
-                  ha->ioctl_datasize = count;
-               } else {
-                  pt->BasicStatus = 0x0B;
-                  pt->ExtendedStatus = 0x00;
-                  SC->result = DID_ERROR << 16;
-
-                  spin_unlock(&ha->ips_lock);
-
-                  return (IPS_FAILURE);
-               }
-            }
-
-      /* copy in the buffer */
-      if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
-                   ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (EFAULT);
-            }
-
-            flash_data.userbuffer = pt->CmdBuffer;
-            flash_data.usersize = pt->CmdBSize;
-            flash_data.kernbuffer = ha->ioctl_data;
-            flash_data.kernsize = ha->ioctl_datasize;
-            flash_data.offset = le32_to_cpu(pt->CoppCP.cmd.flashbios.offset);
-            flash_data.SC = (void *) SC;
-            flash_data.pt = (void *) pt;
-            flash_data.ha = (void *) ha;
-            sema_init( &ha->flash_ioctl_sem, 0 );
-            flash_data.sem = &ha->flash_ioctl_sem;
-
-            task.sync = 0;
-            task.routine = ips_flash_bios_section;
-            task.data = (void *) &flash_data;
-
-            /* Unlock the master lock */
-            spin_unlock_irq(&io_request_lock);
-
-            queue_task(&task, &tq_immediate);
-            mark_bh(IMMEDIATE_BH);
-            
-            /* Wait for the flash to complete */
-            down(&ha->flash_ioctl_sem);
-
-            /* Obtain the master lock */
-            spin_lock_irq(&io_request_lock);
-
-            return (flash_data.retcode);
-         }
-
-         if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
-             (pt->CoppCP.cmd.flashfw.type == 1) &&
-             (pt->CoppCP.cmd.flashfw.direction == 3) &&
-             (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
-            /* Erase the Card BIOS */
-            if (!ha->func.erasebios) {
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-      if ((*ha->func.erasebios)(ha)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-               pt->BasicStatus = 0x0B;
-               pt->ExtendedStatus = 0x00;
-               SC->result = DID_ERROR << 16;
-
-               return (IPS_FAILURE);
-            }
-
-            SC->result = DID_OK << 16;
-            pt->BasicStatus = 0x00;
-            pt->ExtendedStatus = 0x00;
-
-            return (IPS_SUCCESS_IMM);
-         }
-
-         if (ips_newusrcmd(ha, pt, scb))
+         if (ips_usrcmd(ha, pt, scb))
             return (IPS_SUCCESS);
          else
             return (IPS_FAILURE);
-      }
-
+      } 
+     
       break;
 
    } /* end switch */
@@ -2848,149 +2551,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_scheduled_flash_bios                                   */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Flash the BIOS on a Copperhead style controller                        */
-/*   To be called from a task queue                                         */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_scheduled_flash_bios(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   /*
-    * Set initial return codes
-    */
-   SC->result = DID_OK << 16;
-   pt->BasicStatus = 0x00;
-   pt->ExtendedStatus = 0x00;
-   fd->retcode = IPS_SUCCESS_IMM;
-
-   /*
-    * Fix the size/ptr to account for the
-    * flash header
-    */
-   fd->kernbuffer += 0xC0;
-   fd->kernsize -= 0xC0;
-   fd->userbuffer += 0xC0;
-   fd->usersize -= 0xC0;
-
-   if ((*ha->func.erasebios)(ha)) {
-      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-
-   ips_flash_bios_segment(data);
-
-   if (fd->retcode == IPS_FAILURE)
-      return ;
-
-   if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
-                   ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-
-   /* Tell them we are done */
-   if (fd->retcode != IPS_FAILURE)
-      up(fd->sem);
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_flash_bios_section                                     */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   wrapper for ips_flash_bios_segment that raises the semaphore           */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_flash_bios_section(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   /*
-    * Set initial return codes
-    */
-   SC->result = DID_OK << 16;
-   pt->BasicStatus = 0x00;
-   pt->ExtendedStatus = 0x00;
-   fd->retcode = IPS_SUCCESS_IMM;
-
-   ips_flash_bios_segment(data);
-
-   if (fd->retcode != IPS_FAILURE)
-      up(fd->sem);
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_flash_bios_segment                                     */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Flash a portion of the BIOS on a Copperhead style controller           */
-/*   To be called from a task queue                                         */
-/*                                                                          */
-/****************************************************************************/
-static void
-ips_flash_bios_segment(void *data) {
-   ips_ha_t       *ha;
-   Scsi_Cmnd      *SC;
-   ips_passthru_t *pt;
-   IPS_FLASH_DATA *fd;
-
-   fd = (IPS_FLASH_DATA *) data;
-   ha = (ips_ha_t *) fd->ha;
-   pt = (ips_passthru_t *) fd->pt;
-   SC = (Scsi_Cmnd *) fd->SC;
-
-   if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
-      DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
-                ips_name, ha->host_num);
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      SC->result = DID_ERROR << 16;
-      fd->retcode = IPS_FAILURE;
-      up(fd->sem);
-
-      return ;
-   }
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_usrcmd                                                 */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -3074,126 +2634,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_newusrcmd                                              */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Process a user command and make it ready to send                       */
-/*                                                                          */
-/****************************************************************************/
-static int
-ips_newusrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
-   IPS_SG_LIST    *sg_list;
-   char           *user_area;
-   char           *kern_area;
-   uint32_t        datasize;
-
-   METHOD_TRACE("ips_newusrcmd", 1);
-
-   if ((!scb) || (!pt) || (!ha))
-      return (0);
-
-   /* Save the S/G list pointer so it doesn't get clobbered */
-   sg_list = scb->sg_list;
-
-   /* copy in the CP */
-   memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
-   memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
-
-   /* FIX stuff that might be wrong */
-   scb->sg_list = sg_list;
-   scb->scb_busaddr = VIRT_TO_BUS(scb);
-   scb->bus = scb->scsi_cmd->channel;
-   scb->target_id = scb->scsi_cmd->target;
-   scb->lun = scb->scsi_cmd->lun;
-   scb->sg_len = 0;
-   scb->data_len = 0;
-   scb->flags = 0;
-   scb->op_code = 0;
-   scb->callback = ipsintr_done;
-   scb->timeout = ips_cmd_timeout;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-
-   /* we don't support DCDB/READ/WRITE Scatter Gather */
-   if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
-      return (0);
-
-   if (pt->CmdBSize) {
-      if (pt->CmdBSize > ha->ioctl_datasize) {
-         void *bigger_struct;
-         uint32_t count;
-         uint32_t order;
-
-         /* try to allocate a bigger struct */
-         for (count = PAGE_SIZE, order = 0;
-              count < pt->CmdBSize;
-              order++, count <<= 1);
-
-         bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
-         if (bigger_struct) {
-            /* free the old memory */
-            free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-
-            /* use the new memory */
-            ha->ioctl_data = (char *) bigger_struct;
-            ha->ioctl_order = order;
-            ha->ioctl_datasize = count;
-         } else
-            return (0);
-
-      }
-
-      scb->data_busaddr = VIRT_TO_BUS(ha->ioctl_data);
-
-      /* Attempt to copy in the data */
-      user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
-      kern_area = ha->ioctl_data;
-      datasize = *((uint32_t *) &scb->scsi_cmd->cmnd[8]);
-
-      if (copy_from_user(kern_area, user_area, datasize) > 0) {
-         DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data",
-                   ips_name, ha->host_num);
-
-         return (0);
-      }
-
-   } else {
-      scb->data_busaddr = 0L;
-   }
-
-   if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
-
-   if (pt->CmdBSize) {
-      if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-      else
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
-   }
-
-   /* set timeouts */
-   if (pt->TimeOut) {
-      scb->timeout = pt->TimeOut;
-
-      if (pt->TimeOut <= 10)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-      else if (pt->TimeOut <= 60)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
-      else
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-   }
-
-   /* assume success */
-   scb->scsi_cmd->result = DID_OK << 16;
-
-   /* success */
-   return (1);
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_cleanup_passthru                                       */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -3225,8 +2665,6 @@
    pt->BasicStatus = scb->basic_status;
    pt->ExtendedStatus = scb->extended_status;
    pt->AdapterType = ha->ad_type;
-   if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) 
-      up(&ha->ioctl_sem);
 
    if(ha->device_id == IPS_DEVICEID_COPPERHEAD && 
      (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || 
@@ -3725,6 +3163,14 @@
       }
    }
 
+   /* Limit the Active Commands on a Lite Adapter */
+   if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
+       (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
+       (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
+      if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) 
+         ha->max_cmds = MaxLiteCmds;
+   }
+
    /* set controller IDs */
    ha->ha_id[0] = IPS_ADAPTER_ID;
    for (i = 1; i < ha->nbus; i++) {
@@ -3812,17 +3258,7 @@
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_ERROR << 16;
-
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-               uint32_t datasize;
-
-               datasize = 0;
-               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
-               up(&ha->ioctl_sem);
-            } else {
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         }
+            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
          }
 
          ips_freescb(ha, scb);
@@ -3830,17 +3266,7 @@
       case IPS_SUCCESS_IMM:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_OK << 16;
-
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
-               uint32_t datasize;
-
-               datasize = 0;
-               memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
-               up(&ha->ioctl_sem);
-            } else {
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-            }
+            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
          }
 
          ips_freescb(ha, scb);
@@ -3866,22 +3292,12 @@
       switch(ret) {
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
-               up(&ha->ioctl_sem);
-
             scb->scsi_cmd->result = DID_ERROR << 16;
          }
 
          ips_freescb(ha, scb);
          break;
       case IPS_SUCCESS_IMM:
-         if (scb->scsi_cmd) {
-            /* raise the semaphore */
-            if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
-               up(&ha->ioctl_sem);
-         }
-
          ips_freescb(ha, scb);
          break;
       default:
@@ -4012,8 +3428,7 @@
 
       }
 
-      scb->dcdb.cmd_attribute |=
-         ips_command_direction[scb->scsi_cmd->cmnd[0]];
+      scb->dcdb.cmd_attribute = ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
       if (!scb->dcdb.cmd_attribute & 0x3)
          scb->dcdb.transfer_length = 0;
@@ -4626,6 +4041,7 @@
 
          bk_save = scb->breakup;
          scb->breakup = 0;
+         mod_timer(&scb->scsi_cmd->eh_timeout, jiffies + 120 * HZ);
 
          if (scb->sg_count) {
             /* S/G request */
@@ -4727,8 +4143,7 @@
             scb->sg_len = 0;
          }
 
-         scb->dcdb.cmd_attribute |=
-            ips_command_direction[scb->scsi_cmd->cmnd[0]];
+         scb->dcdb.cmd_attribute |= ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
          if (!scb->dcdb.cmd_attribute & 0x3)
             scb->dcdb.transfer_length = 0;
@@ -4771,9 +4186,7 @@
       IPS_HA_UNLOCK(cpu_flags);
    }
 
-   /* call back to SCSI layer */
-   if (scb->scsi_cmd && scb->scsi_cmd->cmnd[0] != IPS_IOCTL_NEW_COMMAND)
-      scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+   scb->scsi_cmd->scsi_done(scb->scsi_cmd);
 
    ips_freescb(ha, scb);
 }
@@ -4791,6 +4204,8 @@
 ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) {
    int       errcode;
    int       device_error;
+   uint32_t  transfer_len;
+   IPS_DCDB_TABLE_TAPE *tapeDCDB;
 
    METHOD_TRACE("ips_map_status", 1);
 
@@ -4832,8 +4247,16 @@
 
          break;
 
-      case IPS_ERR_OU_RUN:
-         if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) {
+      case IPS_ERR_OU_RUN:   
+         if ( ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB ) ||
+              ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG ) ) {
+             tapeDCDB = ( IPS_DCDB_TABLE_TAPE * ) &scb->dcdb;
+             transfer_len = tapeDCDB->transfer_length;
+         } else {
+             transfer_len = ( uint32_t ) scb->dcdb.transfer_length;
+         }
+
+        if ((scb->bus) && (transfer_len < scb->data_len)) {
             /* Underrun - set default to no error */
             errcode = DID_OK;
 
@@ -4864,9 +4287,15 @@
 
       case IPS_ERR_CKCOND:
          if (scb->bus) {
-            memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
-                   sizeof(scb->scsi_cmd->sense_buffer));
-
+            if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
+                (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)) {
+               tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb;
+               memcpy(scb->scsi_cmd->sense_buffer, tapeDCDB->sense_info,
+                      sizeof(scb->scsi_cmd->sense_buffer));
+            } else {
+               memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
+                      sizeof(scb->scsi_cmd->sense_buffer));
+            }
             device_error = 2; /* check condition */
          }
 
@@ -4888,28 +4317,6 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_send                                                   */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Wrapper for ips_send_cmd                                               */
-/*                                                                          */
-/****************************************************************************/
-static int
-ips_send(ips_ha_t *ha, ips_scb_t *scb, ips_scb_callback callback) {
-   int ret;
-
-   METHOD_TRACE("ips_send", 1);
-
-   scb->callback = callback;
-
-   ret = ips_send_cmd(ha, scb);
-
-   return (ret);
-}
-
-/****************************************************************************/
-/*                                                                          */
 /* Routine Name: ips_send_wait                                              */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -4928,9 +4335,9 @@
    if (intr != IPS_FFDC) {      /* Won't be Waiting if this is a Time Stamp */
       ha->waitflag = TRUE;
       ha->cmd_in_progress = scb->cdb[0];
-    }
-
-   ret = ips_send(ha, scb, ipsintr_blocking);
+   }
+   scb->callback = ipsintr_blocking;
+   ret = ips_send_cmd(ha, scb);
 
    if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
       return (ret);
@@ -4955,6 +4362,7 @@
    int       ret;
    char     *sp;
    int       device_error;
+   IPS_DCDB_TABLE_TAPE *tapeDCDB;
 
    METHOD_TRACE("ips_send_cmd", 1);
 
@@ -5183,26 +4591,63 @@
       scb->cmd.dcdb.reserved2 = 0;
       scb->cmd.dcdb.reserved3 = 0;
 
-      scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
-      scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
-
-      if (scb->timeout) {
-         if (scb->timeout <= 10)
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-         else if (scb->timeout <= 60)
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+      if (ha->subsys->param[4] & 0x00100000) {          /* If NEW Tape DCDB is Supported */
+         if (!scb->sg_len)
+            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
          else
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-      }
+            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB_SG;
+ 
+         tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb; /* Use Same Data Area as Old DCDB Struct */
+         tapeDCDB->device_address = ((scb->bus - 1) << 4) | scb->target_id;
+         tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+         tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;   /* Always Turn OFF 64K Size Flag */
+
+         if (scb->timeout) {
+           if (scb->timeout <= 10)
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;
+            else if (scb->timeout <= 60)
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;
+            else
+               tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
+         }
 
-      if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         if (!(tapeDCDB->cmd_attribute & IPS_TIMEOUT20M))
+            tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
 
-      scb->dcdb.sense_length = sizeof(scb->scsi_cmd->sense_buffer);
-      scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-      scb->dcdb.sg_count = scb->sg_len;
-      scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
-      memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
+         tapeDCDB->transfer_length = scb->data_len;
+         tapeDCDB->buffer_pointer = cpu_to_le32(scb->data_busaddr);
+         tapeDCDB->sg_count = scb->sg_len;
+         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+         tapeDCDB->reserved_for_LUN = 0;
+         tapeDCDB->reserved = 0;
+         tapeDCDB->scsi_status = 0;
+         memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+      } else {
+         scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
+         scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+
+         if (scb->timeout) {
+           if (scb->timeout <= 10)
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
+            else if (scb->timeout <= 60)
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+            else
+               scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         }
+
+         if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
+            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+
+         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         scb->dcdb.transfer_length = scb->data_len;
+         if ( scb->dcdb.cmd_attribute & IPS_TRANSFER64K ) 
+             scb->dcdb.transfer_length = 0;
+         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
+         scb->dcdb.sg_count = scb->sg_len;
+         scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+         memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+      }
    }
 
    return ((*ha->func.issue)(ha, scb));
@@ -7808,17 +7253,17 @@
 
  if  (strncmp(FirmwareVersion, Compatable[ ha->nvram->adapter_type ], IPS_COMPAT_ID_LENGTH) != 0)
  {
-     /* if (ips_cd_boot == 0)                                                                              */
-     /*   printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", */
-     /*          ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]);                    */
+     if (ips_cd_boot == 0)                                                                              
+       printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", 
+              ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]);                    
      MatchError = 1;
  }
 
  if  (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
  {
-     /* if (ips_cd_boot == 0)                                                                          */
-     /*   printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", */
-     /*          ha->host_num, BiosVersion, IPS_COMPAT_BIOS);                                          */
+     if (ips_cd_boot == 0)                                                                          
+       printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", 
+              ha->host_num, BiosVersion, IPS_COMPAT_BIOS);                                          
      MatchError = 1;
  }
 
@@ -7827,8 +7272,8 @@
  if  (MatchError)
  {
      ha->nvram->version_mismatch = 1;
-     /* if (ips_cd_boot == 0)                                               */
-     /*  printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n"); */
+     if (ips_cd_boot == 0)                                               
+       printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n");
  }
  else
  {
@@ -7964,6 +7409,7 @@
    uint32_t          count;
    char             *ioremap_ptr;
    char             *mem_ptr;             
+   uint32_t          IsDead
 
    METHOD_TRACE("ips_init_phase1", 1);
    index = IPS_MAX_ADAPTERS;
@@ -8227,6 +7673,14 @@
           ha->func.issue = ips_issue_copperhead;
     }
 
+    if ( IPS_IS_MORPHEUS( ha ) ) {
+        /* If Morpheus appears dead, reset it */
+        IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
+        if ( IsDead == 0xDEADBEEF ) {
+            ips_reset_morpheus( ha );
+        }
+    }
+
     /*
      * Initialize the card if it isn't already
      */
diff -urN linux-2.4.20-pre2/drivers/scsi/ips.h linux-2.4.20-pre3/drivers/scsi/ips.h
--- linux-2.4.20-pre2/drivers/scsi/ips.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/ips.h	Sat Aug 17 14:18:54 2002
@@ -2,6 +2,8 @@
 /* ips.h -- driver for the IBM ServeRAID controller                          */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 1999 IBM Corporation                                        */
 /*                                                                           */
@@ -40,7 +42,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions should be mailed to:                            */
-/*      ipslinux@us.ibm.com                                                  */
+/*      ipslinux@adaptec.com     	                                         */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -168,12 +170,14 @@
    #define IPS_CMD_WRITE_SG             0x83
    #define IPS_CMD_DCDB                 0x04
    #define IPS_CMD_DCDB_SG              0x84
+   #define IPS_CMD_EXTENDED_DCDB 	    0x95
+	#define IPS_CMD_EXTENDED_DCDB_SG		 0x96
    #define IPS_CMD_CONFIG_SYNC          0x58
    #define IPS_CMD_ERROR_TABLE          0x17
    #define IPS_CMD_DOWNLOAD             0x20
    #define IPS_CMD_RW_BIOSFW            0x22
    #define IPS_CMD_GET_VERSION_INFO     0xC6
-   #define IPS_CMD_RESET_CHANNEL        0x1A
+   #define IPS_CMD_RESET_CHANNEL        0x1A  
 
    /*
     * Adapter Equates
@@ -199,7 +203,6 @@
    #define IPS_GOOD_POST_STATUS         0x80
    #define IPS_SEM_TIMEOUT              2000
    #define IPS_IOCTL_COMMAND            0x0D
-   #define IPS_IOCTL_NEW_COMMAND        0x81
    #define IPS_INTR_ON                  0
    #define IPS_INTR_IORL                1
    #define IPS_FFDC                     99
@@ -704,6 +707,21 @@
    uint8_t   reserved2[3];
 } IPS_DCDB_TABLE, *PIPS_DCDB_TABLE;
 
+typedef struct {
+   uint8_t   device_address;
+   uint8_t   cmd_attribute;
+   uint8_t   cdb_length;
+   uint8_t   reserved_for_LUN; 	 
+   uint32_t  transfer_length;
+   uint32_t  buffer_pointer;
+   uint16_t  sg_count;
+   uint8_t   sense_length;
+   uint8_t   scsi_status;
+   uint32_t  reserved;
+   uint8_t   scsi_cdb[16];
+   uint8_t   sense_info[56];
+} IPS_DCDB_TABLE_TAPE, *PIPS_DCDB_TABLE_TAPE;
+
 typedef union {
    struct {
       volatile uint8_t  reserved;
@@ -1206,39 +1224,42 @@
 *
 *************************************************************************/
 
-#define IPS_VER_MAJOR 4
-#define IPS_VER_MAJOR_STRING "4"
-#define IPS_VER_MINOR 90
-#define IPS_VER_MINOR_STRING "90"
-#define IPS_VER_BUILD_STRING "18"
-#define IPS_VER_STRING "4.90.18"
+#define IPS_VER_MAJOR 5
+#define IPS_VER_MAJOR_STRING "5"
+#define IPS_VER_MINOR 10
+#define IPS_VER_MINOR_STRING "10"
+#define IPS_VER_BUILD 21
+#define IPS_VER_BUILD_STRING "21"
+#define IPS_VER_STRING "5.10.21"
 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
+#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
 #define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002."
 
 /* Version numbers for various adapters */
 #define IPS_VER_SERVERAID1 "2.25.01"
 #define IPS_VER_SERVERAID2 "2.88.13"
 #define IPS_VER_NAVAJO "2.88.13"
-#define IPS_VER_SERVERAID3 "3.84.01"
-#define IPS_VER_SERVERAID4H "4.84.01"
-#define IPS_VER_SERVERAID4MLx "4.90.18"
-#define IPS_VER_SARASOTA "0.00.00"
+#define IPS_VER_SERVERAID3 "5.10.21"
+#define IPS_VER_SERVERAID4H "5.10.21"
+#define IPS_VER_SERVERAID4MLx "5.10.21"
+#define IPS_VER_SARASOTA "5.10.21"
 
 /* Compatability IDs for various adapters */
 #define IPS_COMPAT_UNKNOWN ""
+#define IPS_COMPAT_CURRENT "SA510"
 #define IPS_COMPAT_SERVERAID1 "2.25.01"
 #define IPS_COMPAT_SERVERAID2 "2.88.13"
 #define IPS_COMPAT_NAVAJO  "2.88.13"
 #define IPS_COMPAT_KIOWA "2.88.13"
-#define IPS_COMPAT_SERVERAID3H  "3.84.01"
-#define IPS_COMPAT_SERVERAID3L  "3.84.01"
-#define IPS_COMPAT_SERVERAID4H  "4.84.01"
-#define IPS_COMPAT_SERVERAID4M  "MA490"
-#define IPS_COMPAT_SERVERAID4L  "MA490"
-#define IPS_COMPAT_SERVERAID4Mx "MA490"
-#define IPS_COMPAT_SERVERAID4Lx "MA490"
-#define IPS_COMPAT_SARASOTA     "XXXXX"
-#define IPS_COMPAT_BIOS "MA490"
+#define IPS_COMPAT_SERVERAID3H  "SA510"
+#define IPS_COMPAT_SERVERAID3L  "SA510"
+#define IPS_COMPAT_SERVERAID4H  "SA510"
+#define IPS_COMPAT_SERVERAID4M  "SA510"
+#define IPS_COMPAT_SERVERAID4L  "SA510"
+#define IPS_COMPAT_SERVERAID4Mx "SA510"
+#define IPS_COMPAT_SERVERAID4Lx "SA510"
+#define IPS_COMPAT_SARASOTA     "SA510"
+#define IPS_COMPAT_BIOS "SA510"
 
 #define IPS_COMPAT_MAX_ADAPTER_TYPE 14
 #define IPS_COMPAT_ID_LENGTH 8
diff -urN linux-2.4.20-pre2/drivers/scsi/script_asm.pl linux-2.4.20-pre3/drivers/scsi/script_asm.pl
--- linux-2.4.20-pre2/drivers/scsi/script_asm.pl	Sun Nov 21 17:41:43 1999
+++ linux-2.4.20-pre3/drivers/scsi/script_asm.pl	Sat Aug 17 14:18:55 2002
@@ -12,6 +12,7 @@
 #
 #   Support for 53c710 (via -ncr7x0_family switch) added by Richard
 #   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
+#   Renamed to -ncr7x0_family to -ncr710, and added -ncr700 - 5th May 2000.
 #
 #   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
@@ -77,7 +78,7 @@
 # 	and = 0x04_00_00_00
 # 	add = 0x06_00_00_00
 
-if ($ncr7x0_family) {
+if ($ncr700 || $ncr710) {
   %operators = (
     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
@@ -99,7 +100,24 @@
 
 # Table of register addresses
 
-if ($ncr7x0_family) {
+if ($ncr700) {
+  %registers = (
+    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
+    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
+    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
+    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
+    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
+    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34,
+    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+    'DMODE', 52, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+  );
+}
+elsif ($ncr710) {
   %registers = (
     'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
     'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
@@ -171,7 +189,7 @@
 # be escaped, I can't use the join() trick I used for the register
 # regex
 
-if ($ncr7x0_family) {
+if ($ncr700 || $ncr710) {
   $operator = '\||OR|AND|\&|\+';
 }
 else {
@@ -468,7 +486,7 @@
 # Process MOVE length, address, WITH|WHEN phase instruction
     } elsif (/^\s*MOVE\s+(.*)/i) {
 	$rest = $1;
-	if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
+	if (!$ncr700 && ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i)) {
 	    $transfer_addr = $1;
 	    $with_when = $2;
 	    $scsi_phase = $3;
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi.h linux-2.4.20-pre3/drivers/scsi/scsi.h
--- linux-2.4.20-pre2/drivers/scsi/scsi.h	Sat Aug 17 14:18:21 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi.h	Sat Aug 17 14:18:55 2002
@@ -48,7 +48,7 @@
 #if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE))
 #define scsi_to_pci_dma_dir(scsi_dir)	((int)(scsi_dir))
 #else
-extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir)
+static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir)
 {
         if (scsi_dir == SCSI_DATA_UNKNOWN)
                 return PCI_DMA_BIDIRECTIONAL;
@@ -66,7 +66,7 @@
 #if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE))
 #define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
 #else
-extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
+static inline int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
 {
         if (scsi_dir == SCSI_DATA_UNKNOWN)
                 return SBUS_DMA_BIDIRECTIONAL;
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi_debug.c linux-2.4.20-pre3/drivers/scsi/scsi_debug.c
--- linux-2.4.20-pre2/drivers/scsi/scsi_debug.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi_debug.c	Sat Aug 17 14:18:55 2002
@@ -1,4 +1,4 @@
-/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+/* 
  *  linux/kernel/scsi_debug.c
  *
  *  Copyright (C) 1992  Eric Youngdale
@@ -12,9 +12,10 @@
  *
  *  For documentation see http://www.torque.net/sg/sdebug.html
  *
- *   D. Gilbert (dpg) work for MOD device test [20010421]
- *   dpg, work for devfs large number of disks [20010809]
- *   dpg, use vmalloc() more inquiry+mode_sense [20020302]
+ *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
+ *   dpg: work for devfs large number of disks [20010809]
+ *        use vmalloc() more inquiry+mode_sense [20020302]
+ *        add timers for delayed responses [20020721]
  */
 
 #include <linux/config.h>
@@ -33,20 +34,22 @@
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
 
-static char scsi_debug_version_str[] = "Version: 0.58 (20020302)";
+#include "scsi_debug.h"
+
+static const char * scsi_debug_version_str = "Version: 0.61 (20020815)";
+
 
 #ifndef SCSI_CMD_READ_16
 #define SCSI_CMD_READ_16 0x88
@@ -54,29 +57,36 @@
 #ifndef SCSI_CMD_WRITE_16
 #define SCSI_CMD_WRITE_16 0x8a
 #endif
+#ifndef REPORT_LUNS
+#define REPORT_LUNS 0xa0
+#endif
 
 /* A few options that we want selected */
 #define DEF_NR_FAKE_DEVS   1
 #define DEF_DEV_SIZE_MB   8
 #define DEF_FAKE_BLK0   0
+#define DEF_EVERY_NTH   100
+#define DEF_DELAY   1
 
 #define DEF_OPTS   0
 #define SCSI_DEBUG_OPT_NOISE   1
 #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
+#define SCSI_DEBUG_OPT_EVERY_NTH   4
 
 #define OPT_MEDIUM_ERR_ADDR   0x1234
 
 static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
 static int scsi_debug_opts = DEF_OPTS;
+static int scsi_debug_every_nth = DEF_EVERY_NTH;
+static int scsi_debug_cmnd_count = 0;
+static int scsi_debug_delay = DEF_DELAY;
 
 #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
 #define N_HEAD          8
 #define N_SECTOR        32
 #define DEV_READONLY(TGT)      (0)
 #define DEV_REMOVEABLE(TGT)    (0)
-#define DEVICE_TYPE(TGT) (TYPE_DISK);
-
-#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+#define PERIPH_DEVICE_TYPE(TGT) (TYPE_DISK);
 
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
@@ -87,135 +97,116 @@
 
 #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
 
-/* Do not attempt to use a timer to simulate a real disk with latency */
-/* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
-
-#define START_PARTITION 4
-
 /* Time to wait before completing a command */
-#define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
 #define SECT_SIZE_PER(TGT) SECT_SIZE
 
-static int starts[] =
-{N_SECTOR,
- N_HEAD * N_SECTOR,		/* Single cylinder */
- N_HEAD * N_SECTOR * 4,
- 0 /* CAPACITY */, 0};
 
-static unsigned char * fake_storep;
+#define SDEBUG_SENSE_LEN 32
 
-typedef struct sdebug_dev_info {
+struct sdebug_dev_info {
 	Scsi_Device * sdp;
-	unsigned short host_no;
-	unsigned short id;
+	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
 	char reset;
-	char sb_index;
-} Sdebug_dev_info;
-static Sdebug_dev_info * devInfop;
+};
+static struct sdebug_dev_info * devInfop;
+
+typedef void (* done_funct_t) (Scsi_Cmnd *);
+
+struct sdebug_queued_cmd {
+	int in_use;
+	struct timer_list cmnd_timer;
+	done_funct_t done_funct;
+	struct scsi_cmnd * a_cmnd;
+	int scsi_result;
+};
+static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
+
+static unsigned char * fake_storep;	/* ramdisk storage */
+
+static unsigned char broken_buff[SDEBUG_SENSE_LEN];
 
 static int num_aborts = 0;
 static int num_dev_resets = 0;
 static int num_bus_resets = 0;
 static int num_host_resets = 0;
 
-static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
-static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
-
-#include "scsi_debug.h"
-
-typedef void (*done_fct_t) (Scsi_Cmnd *);
+static spinlock_t queued_arr_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t atomic_rw = RW_LOCK_UNLOCKED;
 
-static volatile done_fct_t * do_done = 0;
 
-static struct Scsi_Host * SHpnt = NULL;
-
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip);
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip);
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip);
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip);
-static void scsi_debug_intr_handle(unsigned long);
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+/* function declarations */
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip);
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip);
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+		     int num, struct sdebug_dev_info * devip);
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
+		      struct sdebug_dev_info * devip);
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip);
+static void timer_intr_handler(unsigned long);
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen);
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
-
-static struct timer_list * timeout = 0;
-static Scsi_Cmnd ** SCint = 0;
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip);
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip, 
+			 done_funct_t done, int scsi_result, int delta_jiff);
+static void init_all_queued(void);
+static void stop_all_queued(void);
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
+                           const char * dev_id_str, int dev_id_str_len);
 
-/*
- * Semaphore used to simulate bus lockups.
- */
-static int scsi_debug_lockup = 0;
 
-#define NUM_SENSE_BUFFS 4
-#define SENSE_BUFF_LEN 32
-static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 
 static
-int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block;
 	int upper_blk;
 	unsigned char *buff;
-	int scsi_debug_errsts;
+	int errsts = 0;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long iflags;
-	int i, num, capac;
-	Sdebug_dev_info * devip = NULL;
-	char * sbuff;
-
-	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
-		printk(KERN_INFO "scsi_debug: queue_command: cmd ");
-		for (i = 0, num = SCpnt->cmd_len; i < num; ++i)
-	            printk("%02x ", cmd[i]);
-		printk("   use_sg=%d\n", SCpnt->use_sg);
-	}
-	/*
-	 * If we are being notified of the mid-level reposessing a command
-	 * due to timeout, just return.
-	 */
-	if (done == NULL) {
-		return 0;
-	}
-
-        if (SCpnt->use_sg) { /* just use first element */
-                struct scatterlist *sgpnt = (struct scatterlist *)
-                                                SCpnt->request_buffer;
-
-                buff = sgpnt[0].address;
-                bufflen = sgpnt[0].length;
-                /* READ and WRITE process scatterlist themselves */
+	int num, capac;
+	struct sdebug_dev_info * devip = NULL;
+	unsigned char * sbuff;
+
+	if (done == NULL)
+		return 0;	/* assume mid level reprocessing command */
+
+	if (SCpnt->use_sg) { /* just use first element */
+		struct scatterlist *sgpnt = (struct scatterlist *)
+						SCpnt->request_buffer;
+
+		buff = sgpnt[0].address;
+		bufflen = sgpnt[0].length;
+		/* READ and WRITE process scatterlist themselves */
+	}
+	else 
+		buff = (unsigned char *) SCpnt->request_buffer;
+	if (NULL == buff) {
+		printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n");
+		buff = broken_buff;	/* just point at dummy */
+		bufflen = SDEBUG_SENSE_LEN;
+	}
+
+        if(target == driver_template.this_id) {
+                printk(KERN_WARNING 
+		       "scsi_debug: initiator's id used as target!\n");
+		return schedule_resp(SCpnt, NULL, done, 0, 0);
         }
-        else
-                buff = (unsigned char *) SCpnt->request_buffer;
 
-        /*
-         * If a command comes for the ID of the host itself, just print
-         * a silly message and return.
-         */
-        if(target == 7) {
-                printk(KERN_WARNING "How do you do!\n");
-                SCpnt->result = 0;
-                done(SCpnt);
-                return 0;
-        }
-
-	if ((target > 7) || (SCpnt->lun != 0)) {
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		return 0;
-	}
+	if ((target > driver_template.this_id) || (SCpnt->lun != 0))
+		return schedule_resp(SCpnt, NULL, done, 
+				     DID_NO_CONNECT << 16, 0);
 #if 0
 	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
 	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
@@ -223,101 +214,93 @@
 #endif
 	if (NULL == SCpnt->device->hostdata) {
 		devip = devInfoReg(SCpnt->device);
-		if (NULL == devip) {
-			SCpnt->result = DID_NO_CONNECT << 16;
-			done(SCpnt);
-			return 0;
-		}
+		if (NULL == devip)
+			return schedule_resp(SCpnt, NULL, done, 
+					     DID_NO_CONNECT << 16, 0);
 		SCpnt->device->hostdata = devip;
 	}
 	devip = SCpnt->device->hostdata;
 
+        if ((SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts) &&
+            (scsi_debug_every_nth > 0) &&
+            (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) {
+                scsi_debug_cmnd_count =0;
+                return 0; /* ignore command causing timeout */
+        }
+
 	switch (*cmd) {
 	case INQUIRY:     /* mandatory */
-		scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, 
-						       bufflen, devip);
 		/* assume INQUIRY called first so setup max_cmd_len */
 		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
 			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+		errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
 		break;
 	case REQUEST_SENSE:	/* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
+		/* Since this driver indicates autosense by placing the
+		 * sense buffer in the scsi_cmnd structure in the response
+		 * (when CHECK_CONDITION is set), the mid level shouldn't
+		 * need to call REQUEST_SENSE */
 		if (devip) {
-			sbuff = &sense_buffers[(int)devip->sb_index][0];
-			devip->sb_index = 0; 
+			sbuff = devip->sense_buff;
+			memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? 
+					     bufflen : SDEBUG_SENSE_LEN);
+			mk_sense_buffer(devip, 0, 0x0, 0, 7);
+		} else {
+			memset(buff, 0, bufflen);
+			buff[0] = 0x70;
 		}
-		else
-		    sbuff = &sense_buffers[0][0]; 
-		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
-				     bufflen : SENSE_BUFF_LEN);
-		memset(sbuff, 0, SENSE_BUFF_LEN);
-		sbuff[0] = 0x70;
-		SCpnt->result = 0;
-		done(SCpnt);
-		return 0;
+		break;
 	case START_STOP:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
-		scsi_debug_errsts = 0;
+		errsts = check_reset(SCpnt, devip);
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk(
-					"Medium removal inhibited..."));
-		} else {
-			SCSI_LOG_LLQUEUE(2, 
-					printk("Medium removal enabled..."));
-		}
-		scsi_debug_errsts = 0;
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk("\tMedium removal %s\n",
+			       cmd[4] ? "inhibited" : "enabled");
 		break;
 	case SEND_DIAGNOSTIC:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
 	case TEST_UNIT_READY:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", 
-					   buff, bufflen));
-		if (buff)
-			memset(buff, 0, bufflen);
-		scsi_debug_errsts = 0;
+		memset(buff, 0, bufflen);
 		break;
+        case RESERVE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RESERVE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
+        case RELEASE_10:
+		errsts = check_reset(SCpnt, devip);
+		memset(buff, 0, bufflen);
+                break;
 	case READ_CAPACITY:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
-                SHpnt = SCpnt->host;
+		errsts = check_reset(SCpnt, devip);
 		memset(buff, 0, bufflen);
-		capac = CAPACITY - 1;
-		buff[0] = (capac >> 24);
-		buff[1] = (capac >> 16) & 0xff;
-		buff[2] = (capac >> 8) & 0xff;
-		buff[3] = capac & 0xff;
-		buff[4] = 0;
-		buff[5] = 0;
-		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-		buff[7] = SECT_SIZE_PER(target) & 0xff;
-
-		scsi_debug_errsts = 0;
+		if (bufflen > 7) {
+			capac = CAPACITY - 1;
+			buff[0] = (capac >> 24);
+			buff[1] = (capac >> 16) & 0xff;
+			buff[2] = (capac >> 8) & 0xff;
+			buff[3] = capac & 0xff;
+			buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+			buff[7] = SECT_SIZE_PER(target) & 0xff;
+		}
 		break;
 	case SCSI_CMD_READ_16:	/* SBC-2 */
 	case READ_12:
 	case READ_10:
 	case READ_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_READ_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -326,38 +309,31 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == READ_12) {
+		} else if ((*cmd) == READ_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == READ_10) {
+		} else if ((*cmd) == READ_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
-				    &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+		break;
+	case REPORT_LUNS:
+		errsts = resp_report_luns(cmd, buff, bufflen, devip);
+		break;
 	case SCSI_CMD_WRITE_16:	/* SBC-2 */
 	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
 		upper_blk = 0;
 		if ((*cmd) == SCSI_CMD_WRITE_16) {
 			upper_blk = cmd[5] + (cmd[4] << 8) + 
@@ -366,97 +342,38 @@
 				(cmd[7] << 16) + (cmd[6] << 24);
 			num = cmd[13] + (cmd[12] << 8) + 
 				(cmd[11] << 16) + (cmd[10] << 24);
-		}
-		else if ((*cmd) == WRITE_12) {
+		} else if ((*cmd) == WRITE_12) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[9] + (cmd[8] << 8) + 
 				(cmd[7] << 16) + (cmd[6] << 24);
-		}
-		else if ((*cmd) == WRITE_10) {
+		} else if ((*cmd) == WRITE_10) {
 			block = cmd[5] + (cmd[4] << 8) + 
 				(cmd[3] << 16) + (cmd[2] << 24);
 			num = cmd[8] + (cmd[7] << 8);
-		}
-		else {
+		} else {
 			block = cmd[3] + (cmd[2] << 8) + 
 				((cmd[1] & 0x1f) << 16);
 			num = cmd[4];
 		}
-		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
-				     &scsi_debug_errsts, devip))
-			break;
-		SCpnt->result = 0;
-/* calls bottom half in upper layers before return from scsi_do_...() */
-		(done) (SCpnt);	
-		return 0;
+		errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+		break;
 	case MODE_SENSE:
 	case MODE_SENSE_10:
-		scsi_debug_errsts = 
-		    scsi_debug_mode_sense(cmd, target, buff, bufflen, devip);
+		errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
 		break;
 	default:
 #if 0
 		printk(KERN_INFO "scsi_debug: Unsupported command, "
 		       "opcode=0x%x\n", (int)cmd[0]);
 #endif
-		if (check_reset(SCpnt, devip)) {
-			done(SCpnt);
-			return 0;
-		}
-		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
-				    (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
-		break;
-	}
-
-	spin_lock_irqsave(&mailbox_lock, iflags);
-	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
-		if (timeout[i].function == NULL)
+		if ((errsts = check_reset(SCpnt, devip)))
 			break;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
+		errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+		break;
 	}
-
-	/*
-	 * If all of the slots are full, just return 1.  The new error 
-	 * handling scheme allows this, and the mid-level should queue things.
-	 */
-	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
-		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		spin_unlock_irqrestore(&mailbox_lock, iflags);
-		return 1;
-	}
-	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
-
-#ifdef IMMEDIATE
-	if (!scsi_debug_lockup) {
-		SCpnt->result = scsi_debug_errsts;
-		SCint[i] = SCpnt;
-		do_done[i] = done;
-		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
-	}
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-#else
-
-	SCpnt->result = scsi_debug_errsts;
-	timeout[i].function = scsi_debug_intr_handle;
-	timeout[i].data = i;
-	timeout[i].expires = jiffies + DISK_SPEED;
-	SCint[i] = SCpnt;
-	do_done[i] = done;
-
-	spin_unlock_irqrestore(&mailbox_lock, iflags);
-	add_timer(&timeout[i]);
-	if (!done)
-		printk(KERN_ERR "scsi_debug_queuecommand: "
-		       "done can't be NULL\n");
-
-#if 0
-	printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, 
-	       timeout[i].expires, jiffies);
-#endif
-#endif
-
-	return 0;
+	return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
 }
 
 static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
@@ -464,58 +381,101 @@
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
 	}
-	return -ENOTTY;
+	/* return -ENOTTY; // Unix mandates this but apps get upset */
+	return -EINVAL;
 }
 
-static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip)
 {
 	if (devip->reset) {
 		devip->reset = 0;
-		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
-		SCpnt->result = (COMMAND_COMPLETE << 8) | 
-				(CHECK_CONDITION << 1);
-                return 1;
+		mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	return 0;
 }
 
-#define SDEBUG_MAX_INQ_SZ 58
+#define SDEBUG_LONG_INQ_SZ 58
+#define SDEBUG_MAX_INQ_ARR_SZ 128
 
-static int scsi_debug_inquiry(unsigned char * cmd, int target,
-			      unsigned char * buff, int bufflen,
-			      Sdebug_dev_info * devip)
+static const char * vendor_id = "Linux   ";
+static const char * product_id = "scsi_debug      ";
+static const char * product_rev = "0004";
+
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, 
+			   const char * dev_id_str, int dev_id_str_len)
+{
+	int num;
+
+	/* Two identification descriptors: */
+	/* T10 vendor identifier field format (faked) */
+	arr[0] = 0x2;	/* ASCII */
+	arr[1] = 0x1;
+	arr[2] = 0x0;
+	memcpy(&arr[4], vendor_id, 8);
+	memcpy(&arr[12], product_id, 16);
+	memcpy(&arr[28], dev_id_str, dev_id_str_len);
+	num = 8 + 16 + dev_id_str_len;
+	arr[3] = num;
+	num += 4;
+	/* NAA IEEE registered identifier (faked) */
+	arr[num] = 0x1;	/* binary */
+	arr[num + 1] = 0x3;
+	arr[num + 2] = 0x0;
+	arr[num + 3] = 0x8;
+	arr[num + 4] = 0x51;	/* ieee company id=0x123456 (faked) */
+	arr[num + 5] = 0x23;
+	arr[num + 6] = 0x45;
+	arr[num + 7] = 0x60;
+	arr[num + 8] = (dev_id_num >> 24);
+	arr[num + 9] = (dev_id_num >> 16) & 0xff;
+	arr[num + 10] = (dev_id_num >> 8) & 0xff;
+	arr[num + 11] = dev_id_num & 0xff;
+	return num + 12;
+}
+
+static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
+			int bufflen, struct sdebug_dev_info * devip)
 {
 	unsigned char pq_pdt;
-	unsigned char arr[SDEBUG_MAX_INQ_SZ];
-	int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? 
-			SDEBUG_MAX_INQ_SZ : bufflen;
+	unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+	int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? 
+			SDEBUG_MAX_INQ_ARR_SZ : bufflen;
 
-	SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 	if (bufflen < cmd[4])
 		printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d "
 		       "< alloc_length=%d\n", bufflen, (int)cmd[4]);
 	memset(buff, 0, bufflen);
-	memset(arr, 0, SDEBUG_MAX_INQ_SZ);
-	pq_pdt = DEVICE_TYPE(target);
+	memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+	pq_pdt = PERIPH_DEVICE_TYPE(target);
 	arr[0] = pq_pdt;
 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-	}
-	else if (0x1 & cmd[1]) {  /* EVPD bit set */
+	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
+		int dev_id_num, len;
+		char dev_id_str[6];
+		
+		dev_id_num = ((devip->sdp->host->host_no + 1) * 1000) + 
+			      devip->sdp->id;
+		len = snprintf(dev_id_str, 6, "%d", dev_id_num);
+		len = (len > 6) ? 6 : len;
 		if (0 == cmd[2]) { /* supported vital product data pages */
-			arr[3] = 1;
-			arr[4] = 0x80; /* ... only unit serial number */
-		}
-		else if (0x80 == cmd[2]) { /* unit serial number */
+			arr[3] = 3;
+			arr[4] = 0x0; /* this page */
+			arr[5] = 0x80; /* unit serial number */
+			arr[6] = 0x83; /* device identification */
+		} else if (0x80 == cmd[2]) { /* unit serial number */
 			arr[1] = 0x80;
-			arr[3] = 4;
-			arr[4] = '1'; arr[5] = '2'; arr[6] = '3';
-			arr[7] = '4';
-		}
-		else {
+			arr[3] = len;
+			memcpy(&arr[4], dev_id_str, len);
+		} else if (0x83 == cmd[2]) { /* device identification */
+			arr[1] = 0x83;
+			arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
+						 dev_id_str, len);
+		} else {
 			/* Illegal request, invalid field in cdb */
-			mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 			return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 		}
 		memcpy(buff, arr, min_len); 
@@ -524,18 +484,18 @@
 	/* drops through here for a standard inquiry */
 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
 	arr[2] = 3;	/* claim SCSI 3 */
-	arr[4] = SDEBUG_MAX_INQ_SZ - 5;
+	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
-	memcpy(&arr[8], "Linux   ", 8);
-	memcpy(&arr[16], "scsi_debug      ", 16);
-	memcpy(&arr[32], "0003", 4);
+	memcpy(&arr[8], vendor_id, 8);
+	memcpy(&arr[16], product_id, 16);
+	memcpy(&arr[32], product_rev, 4);
 	memcpy(buff, arr, min_len);
 	return 0;
 }
 
 /* <<Following mode page info copied from ST318451LW>> */ 
 
-static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target)
+static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
 {	/* Read-Write Error Recovery page for mode_sense */
 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 
 					5, 0, 0xff, 0xff};
@@ -546,7 +506,7 @@
 	return sizeof(err_recov_pg);
 }
 
-static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target)
+static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Disconnect-Reconnect page for mode_sense */
 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 
 					 0, 0, 0, 0, 0, 0, 0, 0};
@@ -557,7 +517,25 @@
 	return sizeof(disconnect_pg);
 }
 
-static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target)
+static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+{       /* Format device page for mode_sense */
+        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0x40, 0, 0, 0};
+
+        memcpy(p, format_pg, sizeof(format_pg));
+        p[10] = (N_SECTOR >> 8) & 0xff;
+        p[11] = N_SECTOR & 0xff;
+        p[12] = (SECT_SIZE >> 8) & 0xff;
+        p[13] = SECT_SIZE & 0xff;
+        if (DEV_REMOVEABLE(target))
+                p[20] |= 0x20; /* should agree with INQUIRY */
+        if (1 == pcontrol)
+                memset(p + 2, 0, sizeof(format_pg) - 2);
+        return sizeof(format_pg);
+}
+
+static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Caching page for mode_sense */
 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 
 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
@@ -568,7 +546,7 @@
 	return sizeof(caching_pg);
 }
 
-static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
 { 	/* Control mode page for mode_sense */
 	unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
 				     0, 0, 0x2, 0x4b};
@@ -582,9 +560,9 @@
 
 #define SDEBUG_MAX_MSENSE_SZ 256
 
-static int scsi_debug_mode_sense(unsigned char * cmd, int target,
-			         unsigned char * buff, int bufflen,
-			         Sdebug_dev_info * devip)
+static int resp_mode_sense(unsigned char * cmd, int target,
+			   unsigned char * buff, int bufflen,
+			   struct sdebug_dev_info * devip)
 {
 	unsigned char dbd;
 	int pcontrol, pcode;
@@ -610,15 +588,14 @@
 	memset(buff, 0, bufflen);
 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
 	if (0x3 == pcontrol) {  /* Saving values not supported */
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
 	if (msense_6) {
 		arr[2] = dev_spec;
 		offset = 4;
-	}
-	else {
+	} else {
 		arr[3] = dev_spec;
 		offset = 8;
 	}
@@ -626,30 +603,34 @@
 
 	switch (pcode) {
 	case 0x1:	/* Read-Write error recovery page, direct access */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x2:	/* Disconnect-Reconnect page, all devices */
-		len = sdebug_disconnect_pg(ap, pcontrol, target);
+		len = resp_disconnect_pg(ap, pcontrol, target);
 		offset += len;
 		break;
+        case 0x3:       /* Format device page, direct access */
+                len = resp_format_pg(ap, pcontrol, target);
+                offset += len;
+                break;
 	case 0x8:	/* Caching page, direct access */
-		len = sdebug_caching_pg(ap, pcontrol, target);
+		len = resp_caching_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0xa:	/* Control Mode page, all devices */
-		len = sdebug_ctrl_m_pg(ap, pcontrol, target);
+		len = resp_ctrl_m_pg(ap, pcontrol, target);
 		offset += len;
 		break;
 	case 0x3f:	/* Read all Mode pages */
-		len = sdebug_err_recov_pg(ap, pcontrol, target);
-		len += sdebug_disconnect_pg(ap + len, pcontrol, target);
-		len += sdebug_caching_pg(ap + len, pcontrol, target);
-		len += sdebug_ctrl_m_pg(ap + len, pcontrol, target);
+		len = resp_err_recov_pg(ap, pcontrol, target);
+		len += resp_disconnect_pg(ap + len, pcontrol, target);
+		len += resp_caching_pg(ap + len, pcontrol, target);
+		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
 		offset += len;
 		break;
 	default:
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	if (msense_6)
@@ -663,8 +644,8 @@
 	return 0;
 }
 
-static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			   int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		     struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -673,30 +654,17 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
-	}
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-	{
-		int delay = SCSI_SETUP_LATENCY;
-
-		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-		if (delay)
-			usleep(delay);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-#endif
 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
 	    (block >= OPT_MEDIUM_ERR_ADDR) && 
 	    (block < (OPT_MEDIUM_ERR_ADDR + num))) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14);
+		mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14);
 		/* claim unrecoverable read error */
-		return 1;
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+	read_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", 
@@ -707,24 +675,8 @@
 		buff = sgpnt[sgcount].address;
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen);
-#if 0
-		/* Simulate a disk change */
-		if (block == 0xfff0) {
-			sense_buffer[0] = 0x70;
-			sense_buffer[2] = UNIT_ATTENTION;
-			starts[0] += 10;
-			starts[1] += 10;
-			starts[2] += 10;
-
-			*errstsp = (COMMAND_COMPLETE << 8) | 
-				   (CHECK_CONDITION << 1);
-			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
-			return 1;
-		}	/* End phony disk change code */
-#endif
 		nbytes -= bufflen;
 		if (SCpnt->use_sg) {
 			block += bufflen >> POW2_SECT_SIZE;
@@ -733,17 +685,16 @@
 				buff = sgpnt[sgcount].address;
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_read: unexpected "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_read: unexpected "
 			       "nbytes=%d\n", nbytes);
 	} while (nbytes);
-	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	read_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
-			    int num, int * errstsp, Sdebug_dev_info * devip)
+static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
+		      struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -752,13 +703,11 @@
 	unsigned long iflags;
 
 	if (upper_blk || (block + num > CAPACITY)) {
-		*errstsp = (COMMAND_COMPLETE << 8) |
-			   (CHECK_CONDITION << 1);
-		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
-		return 1;
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 
-	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+	write_lock_irqsave(&atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
 	if (SCpnt->use_sg) {
@@ -767,7 +716,6 @@
 		buff = sgpnt[sgcount].address;
 		bufflen = sgpnt[sgcount].length;
 	}
-	*errstsp = 0;
 	do {
 		memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen);
 
@@ -779,101 +727,61 @@
 				buff = sgpnt[sgcount].address;
 				bufflen = sgpnt[sgcount].length;
 			}
-		}
-		else if (nbytes > 0)
-			printk(KERN_WARNING "sdebug_write: "
+		} else if (nbytes > 0)
+			printk(KERN_WARNING "scsi_debug:resp_write: "
 			       "unexpected nbytes=%d\n", nbytes);
 	} while (nbytes);
-	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	write_unlock_irqrestore(&atomic_rw, iflags);
 	return 0;
 }
 
-/* A "high" level interrupt handler.  This should be called once per jiffy
- * to simulate a regular scsi disk.  We use a timer to do this. */
-
-static void scsi_debug_intr_handle(unsigned long indx)
+static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
+			    int bufflen, struct sdebug_dev_info * devip)
 {
-	Scsi_Cmnd *SCtmp;
-	void (*my_done) (Scsi_Cmnd *);
-#if 0
-	del_timer(&timeout[indx]);
-#endif
-
-	SCtmp = (Scsi_Cmnd *) SCint[indx];
-	my_done = do_done[indx];
-	do_done[indx] = NULL;
-	timeout[indx].function = NULL;
-	SCint[indx] = NULL;
+	unsigned int alloc_len;
+	int select_report = (int)cmd[2];
 
-	if (!my_done) {
-		printk(KERN_ERR "scsi_debug_intr_handle: Unexpected "
-		       "interrupt\n");
-		return;
+	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+	if ((alloc_len < 16) || (select_report > 2)) {
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
-#if 0
-	printk(KERN_INFO "In intr_handle...");
-	printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies);
-	printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done);
-#endif
-
-	my_done(SCtmp);
-#if 0
-	printk(KERN_INFO "Called done.\n");
-#endif
+	if (bufflen > 3) {
+		memset(buff, 0, bufflen);
+		buff[3] = 8;
+	}
+	return 0;
 }
 
-static int initialized = 0;
-
-static int do_init(void)
+/* When timer goes off this function is called. */
+static void timer_intr_handler(unsigned long indx)
 {
-	int sz = STORE_SIZE;
-
-	starts[3] = CAPACITY;
-	fake_storep = vmalloc(sz);
-	if (NULL == fake_storep)
-		return 1;
-	memset(fake_storep, 0, sz);
-
-	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
-	do_done = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == do_done)
-		goto out;
-	memset((void *)do_done, 0, sz);
-
-	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
-	timeout = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == timeout)
-		goto out;
-	memset(timeout, 0, sz);
-
-	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
-	SCint = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == SCint)
-		goto out;
-	memset(SCint, 0, sz);
+	struct sdebug_queued_cmd * sqcp;
+	unsigned int iflags;
 
-	return 0;
-
-out:
-	if (fake_storep)
-		vfree(fake_storep);
-	if (do_done)
-		kfree((void *)do_done);
-	if (timeout)
-		kfree(timeout);
-	if (SCint)
-		kfree(SCint);
-	return 1;
-}
-
-static void do_end(void)
-{
-	kfree(SCint);
-	kfree(timeout);
-	kfree((void *)do_done);
-	vfree(fake_storep);
+	if (indx >= SCSI_DEBUG_CANQUEUE) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
+		       "large\n");
+		return;
+	}
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	sqcp = &queued_arr[(int)indx];
+	if (! sqcp->in_use) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
+		       "interrupt\n");
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return;
+	}
+	sqcp->in_use = 0;
+	if (sqcp->done_funct)
+		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
+	sqcp->done_funct = NULL;
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
+static int initialized = 0;
+static int num_present = 0;
+static const char * sdebug_proc_name = "scsi_debug";
 
 static int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
@@ -883,28 +791,33 @@
 		printk(KERN_INFO "scsi_debug: detect\n");
 	if (0 == initialized) {
 		++initialized;
-		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
-		devInfop = kmalloc(sz, GFP_ATOMIC);
+		sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = vmalloc(sz);
 		if (NULL == devInfop) {
 			printk(KERN_ERR "scsi_debug_detect: out of "
 			       "memory, 0.5\n");
 			return 0;
 		}
 		memset(devInfop, 0, sz);
-		if (do_init()) {
+		sz = STORE_SIZE;
+		fake_storep = vmalloc(sz);
+		if (NULL == fake_storep) {
 			printk(KERN_ERR "scsi_debug_detect: out of memory"
 			       ", 0\n");
 			return 0;
 		}
-		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
-			sense_buffers[k][0] = 0x70;
-		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
-			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
-			scsi_register(tpnt, 0);
+		memset(fake_storep, 0, sz);
+		init_all_queued();
+		tpnt->proc_name = (char *)sdebug_proc_name;
+		for (num_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
+			if (NULL == scsi_register(tpnt, 0))
+				printk(KERN_ERR "scsi_debug_detect: "
+					"scsi_register failed k=%d\n", k);
+			else
+				++num_present;
 		}
-		return NR_HOSTS_PRESENT;
-	}
-	else {
+		return num_present;
+	} else {
 		printk(KERN_WARNING "scsi_debug_detect: called again\n");
 		return 0;
 	}
@@ -917,51 +830,47 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: release\n");
+	stop_all_queued();
 	scsi_unregister(hpnt);
-	if (++num_releases != NR_HOSTS_PRESENT)
-		return 0;
-	do_end();
-	kfree(devInfop);
+	if (++num_releases == num_present) {
+		vfree(fake_storep);
+		vfree(devInfop);
+	}
 	return 0;
 }
 
-static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+static struct sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
 {
 	int k;
-	unsigned short host_no, id;
-	Sdebug_dev_info * devip;
+	struct sdebug_dev_info * devip;
 
-	host_no = sdp->host->host_no;
-	id = (unsigned short)sdp->id;
 	for (k = 0; k < scsi_debug_num_devs; ++k) {
 		devip = &devInfop[k];
-		if (devip->sdp && (host_no == devip->host_no) &&
-		    (id == devip->id)) {
-			devip->sdp = sdp; /* overwrite previous sdp */
+		if (devip->sdp == sdp)
 			return devip;
-		}
+	}
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
 		if (NULL == devip->sdp) {
 			devip->sdp = sdp;
-			devip->host_no = host_no;
-			devip->id = id;
 			devip->reset = 1;
-			devip->sb_index = 0;
+			memset(devip->sense_buff, 0, SDEBUG_SENSE_LEN);
+			devip->sense_buff[0] = 0x70;
 			return devip;
 		}
 	}
 	return NULL;
 }
 
-static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen)
 {
-	char * sbuff;
-	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
-		return;
-	if (devip)
-		devip->sb_index = index;
-	sbuff = &sense_buffers[index][0];
-	memset(sbuff, 0, SENSE_BUFF_LEN);
+	unsigned char * sbuff;
+
+	sbuff = devip->sense_buff;
+	memset(sbuff, 0, SDEBUG_SENSE_LEN);
+	if (inbandLen > SDEBUG_SENSE_LEN)
+		inbandLen = SDEBUG_SENSE_LEN;
 	sbuff[0] = 0x70;
 	sbuff[2] = key;
 	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
@@ -973,27 +882,9 @@
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: abort\n");
-#if 1
 	++num_aborts;
+	stop_queued_cmnd(SCpnt);
 	return SUCCESS;
-#else
-	int j;
-	void (*my_done) (Scsi_Cmnd *);
-	unsigned long iflags;
-	SCpnt->result = SCpnt->abort_reason << 16;
-	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
-		if (SCpnt == SCint[j]) {
-			my_done = do_done[j];
-			my_done(SCpnt);
-			spin_lock_irqsave(&mailbox_lock, iflags);
-			timeout[j] = 0;
-			SCint[j] = NULL;
-			do_done[j] = NULL;
-			spin_unlock_irqrestore(&mailbox_lock, iflags);
-		}
-	}
-	return SCSI_ABORT_SNOOZE;
-#endif
 }
 
 static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
@@ -1055,12 +946,124 @@
 	++num_host_resets;
 	for (k = 0; k < scsi_debug_num_devs; ++k)
 		devInfop[k].reset = 1;
+	stop_all_queued();
 
 	return SUCCESS;
 }
 
+/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+}
+
+/* Deletes (stops) timers of all queued commands */
+static void stop_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && sqcp->a_cmnd) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+/* Initializes timers in queued array */
+static void init_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		init_timer(&sqcp->cmnd_timer);
+		sqcp->in_use = 0;
+		sqcp->a_cmnd = NULL;
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+static int schedule_resp(struct scsi_cmnd * cmnd, 
+			 struct sdebug_dev_info * devip,
+			 done_funct_t done, int scsi_result, int delta_jiff)
+{
+	int k, num; 
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: cmd ");
+		for (k = 0, num = cmnd->cmd_len; k < num; ++k)
+	            printk("%02x ", (int)cmnd->cmnd[k]);
+		printk("result=0x%x\n", scsi_result);
+	}
+	if (cmnd && devip) {
+		/* simulate autosense by this driver */
+		if (CHECK_CONDITION == status_byte(scsi_result))
+			memcpy(cmnd->sense_buffer, devip->sense_buff, 
+			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
+			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
+	}
+	if (delta_jiff <= 0) {
+		if (cmnd)
+			cmnd->result = scsi_result;
+		if (done)
+			done(cmnd);
+		return 0;
+	} else {
+		unsigned long iflags;
+		int k;
+		struct sdebug_queued_cmd * sqcp = NULL;
+
+		spin_lock_irqsave(&queued_arr_lock, iflags);
+		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+			sqcp = &queued_arr[k];
+			if (! sqcp->in_use)
+				break;
+		}
+		if (k >= SCSI_DEBUG_CANQUEUE) {
+			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
+			return 1;	/* report busy to mid level */
+		}
+		sqcp->in_use = 1;
+		sqcp->a_cmnd = cmnd;
+		sqcp->scsi_result = scsi_result;
+		sqcp->done_funct = done;
+		sqcp->cmnd_timer.function = timer_intr_handler;
+		sqcp->cmnd_timer.data = k;
+		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
+		add_timer(&sqcp->cmnd_timer);
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return 0;
+	}
+}
+
 #ifndef MODULE
-static int __init scsi_debug_num_devs_setup(char *str)
+static int __init num_devs_setup(char *str)
 {   
     int tmp; 
     
@@ -1074,10 +1077,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_num_devs=", num_devs_setup);
 
-__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
-
-static int __init scsi_debug_dev_size_mb_setup(char *str)
+static int __init dev_size_mb_setup(char *str)
 {   
     int tmp; 
     
@@ -1092,10 +1094,9 @@
         return 0;
     }
 }
+__setup("scsi_debug_dev_size_mb=", dev_size_mb_setup);
 
-__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
-
-static int __init scsi_debug_opts_setup(char *str)
+static int __init opts_setup(char *str)
 {   
     int tmp; 
     
@@ -1110,8 +1111,41 @@
         return 0;
     }
 }
+__setup("scsi_debug_opts=", opts_setup);
+
+static int __init every_nth_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_every_nth = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_every_nth: usage "
+               "scsi_debug_every_nth=<n>\n"
+               "    timeout every nth command (when ...)\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_every_nth=", every_nth_setup);
+
+static int __init delay_setup(char *str)
+{
+    int tmp;
+
+    if (get_option(&str, &tmp) == 1) {
+	scsi_debug_delay = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_delay: usage "
+               "scsi_debug_delay=<n>\n"
+               "    delay response <n> jiffies\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_delay=", delay_setup);
 
-__setup("scsi_debug_opts=", scsi_debug_opts_setup);
 #endif
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
@@ -1122,14 +1156,17 @@
 MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
 MODULE_PARM(scsi_debug_opts, "i");
 MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->...");
-
+MODULE_PARM(scsi_debug_every_nth, "i");
+MODULE_PARM_DESC(scsi_debug_every_nth, "timeout every nth command(def=100)");
+MODULE_PARM(scsi_debug_delay, "i");
+MODULE_PARM_DESC(scsi_debug_delay, "# of jiffies to delay response(def=1)");
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
 #endif
 
 static char sdebug_info[256];
 
-const char * scsi_debug_info(struct Scsi_Host * shp)
+static const char * scsi_debug_info(struct Scsi_Host * shp)
 {
 	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
 		"dev_size_mb=%d, opts=0x%x", scsi_debug_version_str,
@@ -1141,8 +1178,8 @@
 /* scsi_debug_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
-int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
-			 int length, int inode, int inout)
+static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
+				int length, int inode, int inout)
 {
 	int len, pos, begin;
 	int orig_length;
@@ -1160,17 +1197,21 @@
 		if (1 != sscanf(arr, "%d", &pos))
 			return -EINVAL;
 		scsi_debug_opts = pos;
+		if (SCSI_DEBUG_OPT_EVERY_NTH & scsi_debug_opts)
+                        scsi_debug_cmnd_count = 0;
 		return length;
 	}
 	begin = 0;
 	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
-	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n"
-	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
-	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
+	    "every_nth=%d(curr:%d)\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d, "
+	    "delay=%d\nnumber of aborts=%d, device_reset=%d, bus_resets=%d, " 
 	    "host_resets=%d\n",
 	    scsi_debug_version_str, scsi_debug_num_devs, 
-	    scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE,
-	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
+	    scsi_debug_cmnd_count,
+	    SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, scsi_debug_delay,
 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
 	if (pos < offset) {
 		len = 0;
@@ -1184,8 +1225,4 @@
 	return (len);
 }
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
-
 #include "scsi_module.c"
-
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi_debug.h linux-2.4.20-pre3/drivers/scsi/scsi_debug.h
--- linux-2.4.20-pre2/drivers/scsi/scsi_debug.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi_debug.h	Sat Aug 17 14:18:55 2002
@@ -4,24 +4,22 @@
 #include <linux/kdev_t.h>
 
 static int scsi_debug_detect(Scsi_Host_Template *);
+static int scsi_debug_release(struct Scsi_Host *);
 /* static int scsi_debug_command(Scsi_Cmnd *); */
 static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int scsi_debug_abort(Scsi_Cmnd *);
+static int scsi_debug_ioctl(Scsi_Device *, int, void *);
 static int scsi_debug_biosparam(Disk *, kdev_t, int[]);
+static int scsi_debug_abort(Scsi_Cmnd *);
 static int scsi_debug_bus_reset(Scsi_Cmnd *);
 static int scsi_debug_device_reset(Scsi_Cmnd *);
 static int scsi_debug_host_reset(Scsi_Cmnd *);
 static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
 static const char * scsi_debug_info(struct Scsi_Host *);
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 /*
  * This driver is written for the lk 2.4 series
  */
-#define SCSI_DEBUG_CANQUEUE  255
+#define SCSI_DEBUG_CANQUEUE  255 	/* needs to be >= 1 */
 
 #define SCSI_DEBUG_MAX_CMD_LEN 16
 
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi_error.c linux-2.4.20-pre3/drivers/scsi/scsi_error.c
--- linux-2.4.20-pre2/drivers/scsi/scsi_error.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi_error.c	Sat Aug 17 14:18:55 2002
@@ -1884,7 +1884,7 @@
 	/*
 	 * Wake up the thread that created us.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", sem_getcount(host->eh_notify)));
 
 	up(host->eh_notify);
 
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi_lib.c linux-2.4.20-pre3/drivers/scsi/scsi_lib.c
--- linux-2.4.20-pre2/drivers/scsi/scsi_lib.c	Sat Aug 17 14:18:21 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi_lib.c	Sat Aug 17 14:18:55 2002
@@ -696,7 +696,7 @@
 
 		switch (SCpnt->sense_buffer[2]) {
 		case ILLEGAL_REQUEST:
-			if (SCpnt->device->ten) {
+			if (SCpnt->device->ten && SCSI_RETRY_10(SCpnt->cmnd[0])) {
 				SCpnt->device->ten = 0;
 				/*
 				 * This will cause a retry with a 6-byte
diff -urN linux-2.4.20-pre2/drivers/scsi/scsi_scan.c linux-2.4.20-pre3/drivers/scsi/scsi_scan.c
--- linux-2.4.20-pre2/drivers/scsi/scsi_scan.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/scsi/scsi_scan.c	Sat Aug 17 14:18:55 2002
@@ -181,6 +181,7 @@
 	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
 	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
 	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 
 	/*
 	 * Must be at end of list...
diff -urN linux-2.4.20-pre2/drivers/sgi/char/sgiserial.h linux-2.4.20-pre3/drivers/sgi/char/sgiserial.h
--- linux-2.4.20-pre2/drivers/sgi/char/sgiserial.h	Mon Aug 27 08:56:31 2001
+++ linux-2.4.20-pre3/drivers/sgi/char/sgiserial.h	Sat Aug 17 14:18:55 2002
@@ -406,7 +406,7 @@
 /* Read Register 15 (value of WR 15) */
 
 /* Misc inlines */
-extern inline void ZS_CLEARERR(struct sgi_zschannel *channel)
+static inline void ZS_CLEARERR(struct sgi_zschannel *channel)
 {
 	volatile unsigned char junk;
 
@@ -416,7 +416,7 @@
 		junk = ioc_icontrol->istat0;
 }
 
-extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
+static inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
 {
 	volatile unsigned char junk;
 
diff -urN linux-2.4.20-pre2/drivers/sound/Config.in linux-2.4.20-pre3/drivers/sound/Config.in
--- linux-2.4.20-pre2/drivers/sound/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/sound/Config.in	Sat Aug 17 14:18:55 2002
@@ -6,6 +6,7 @@
 
 # Prompt user for primary drivers.
 
+dep_tristate '  ALi5455 audio support' CONFIG_SOUND_ALI5455 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  BT878 audio dma' CONFIG_SOUND_BT878 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
@@ -207,7 +208,7 @@
          bool '      Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
       fi
    fi
-	 
+
    if [ "$CONFIG_ARM" = "y" ]; then
       if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
          dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
diff -urN linux-2.4.20-pre2/drivers/sound/Makefile linux-2.4.20-pre3/drivers/sound/Makefile
--- linux-2.4.20-pre2/drivers/sound/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/sound/Makefile	Sat Aug 17 14:18:55 2002
@@ -22,6 +22,7 @@
 
 obj-$(CONFIG_SOUND_HAL2)	+= hal2.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
+obj-$(CONFIG_SOUND_ALI5455)	+= ali5455.o ac97_codec.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_OPL3SA1)	+= opl3sa.o ad1848.o uart401.o
@@ -71,6 +72,7 @@
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_MAESTRO3)	+= maestro3.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
+obj-$(CONFIG_SOUND_HARMONY)	+= harmony.o
 obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
diff -urN linux-2.4.20-pre2/drivers/sound/ac97_codec.c linux-2.4.20-pre3/drivers/sound/ac97_codec.c
--- linux-2.4.20-pre2/drivers/sound/ac97_codec.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre3/drivers/sound/ac97_codec.c	Sat Aug 17 14:18:55 2002
@@ -698,7 +698,8 @@
 
 	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
 		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       codec->id ? "Secondary" : "Primary");
+		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
+		       : (codec->id&1 ? "Secondary":  "Primary"));
 		return 0;
 	}
 
diff -urN linux-2.4.20-pre2/drivers/sound/ali5455.c linux-2.4.20-pre3/drivers/sound/ali5455.c
--- linux-2.4.20-pre2/drivers/sound/ali5455.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/drivers/sound/ali5455.c	Sat Aug 17 14:18:55 2002
@@ -0,0 +1,3731 @@
+/*
+ *	ALI  ali5455 and friends ICH driver for Linux
+ *	LEI HU <Lei_Hu@ali.com.tw>
+ *
+ *  Built from:
+ *	drivers/sound/i810_audio
+ *
+ *  	The ALi 5455 is similar but not quite identical to the Intel ICH
+ *	series of controllers. Its easier to keep the driver seperated from
+ *	the i810 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.
+ *
+ *
+ *	ALi 5455 theory of operation
+ *
+ *	The chipset provides three DMA channels that talk to an AC97
+ *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
+ *	you get 48Khz audio with basic volume and mixer controls. At the
+ *	best you get rate adaption in the codec. We set the card up so
+ *	that we never take completion interrupts but instead keep the card
+ *	chasing its tail around a ring buffer. This is needed for mmap
+ *	mode audio and happens to work rather well for non-mmap modes too.
+ *
+ *	The board has one output channel for PCM audio (supported) and
+ *	a stereo line in and mono microphone input. Again these are normally
+ *	locked to 48Khz only. Right now recording is not finished.
+ *
+ *	There is no midi support, no synth support. Use timidity. To get
+ *	esd working you need to use esd -r 48000 as it won't probe 48KHz
+ *	by default. mpg123 can't handle 48Khz only audio so use xmms.
+ *
+ *	If you need to force a specific rate set the clocking= option
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/ac97_codec.h>
+#include <linux/wrapper.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#ifndef PCI_DEVICE_ID_ALI_5455
+#define PCI_DEVICE_ID_ALI_5455	0x5455
+#endif
+
+#ifndef PCI_VENDOR_ID_ALI
+#define PCI_VENDOR_ID_ALI	0x10b9
+#endif
+
+static int strict_clocking = 0;
+static unsigned int clocking = 0;
+static unsigned int codec_pcmout_share_spdif_locked = 0;
+static unsigned int codec_independent_spdif_locked = 0;
+static unsigned int controller_pcmout_share_spdif_locked = 0;
+static unsigned int controller_independent_spdif_locked = 0;
+static unsigned int globel = 0;
+
+#define ADC_RUNNING	1
+#define DAC_RUNNING	2
+#define CODEC_SPDIFOUT_RUNNING 8
+#define CONTROLLER_SPDIFOUT_RUNNING 4
+
+#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */
+
+#define ALI5455_FMT_16BIT	1
+#define ALI5455_FMT_STEREO	2
+#define ALI5455_FMT_MASK	3
+
+#define SPDIF_ON	0x0004
+#define SURR_ON		0x0010
+#define CENTER_LFE_ON	0x0020
+#define VOL_MUTED	0x8000
+
+
+#define ALI_SPDIF_OUT_CH_STATUS 0xbf
+/* the 810's array of pointers to data buffers */
+
+struct sg_item {
+#define BUSADDR_MASK	0xFFFFFFFE
+	u32 busaddr;
+#define CON_IOC 	0x80000000	/* interrupt on completion */
+#define CON_BUFPAD	0x40000000	/* pad underrun with last sample, else 0 */
+#define CON_BUFLEN_MASK	0x0000ffff	/* buffer length in samples */
+	u32 control;
+};
+
+/* an instance of the ali channel */
+#define SG_LEN 32
+struct ali_channel {
+	/* these sg guys should probably be allocated
+	   seperately as nocache. Must be 8 byte aligned */
+	struct sg_item sg[SG_LEN];	/* 32*8 */
+	u32 offset;		/* 4 */
+	u32 port;		/* 4 */
+	u32 used;
+	u32 num;
+};
+
+/*
+ * we have 3 seperate dma engines.  pcm in, pcm out, and mic.
+ * each dma engine has controlling registers.  These goofy
+ * names are from the datasheet, but make it easy to write
+ * code while leafing through it.
+ */
+
+#define ENUM_ENGINE(PRE,DIG) 									\
+enum {												\
+	PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\
+	PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\
+	PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\
+	PRE##_SR =	0x##DIG##6,		/* Status Register */				\
+	PRE##_PICB =	0x##DIG##8,		/* Position In Current Buffer */		\
+	PRE##_CR =	0x##DIG##b		/* Control Register */				\
+}
+
+ENUM_ENGINE(OFF, 0);		/* Offsets */
+ENUM_ENGINE(PI, 4);		/* PCM In */
+ENUM_ENGINE(PO, 5);		/* PCM Out */
+ENUM_ENGINE(MC, 6);		/* Mic In */
+ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */
+ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */
+ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */
+
+
+enum {
+	ALI_SCR = 0x00,		/* System Control Register */
+	ALI_SSR = 0x04,		/* System Status Register  */
+	ALI_DMACR = 0x08,	/* DMA Control Register    */
+	ALI_FIFOCR1 = 0x0c,	/* FIFO Control Register 1  */
+	ALI_INTERFACECR = 0x10,	/* Interface Control Register */
+	ALI_INTERRUPTCR = 0x14,	/* Interrupt control Register */
+	ALI_INTERRUPTSR = 0x18,	/* Interrupt  Status Register */
+	ALI_FIFOCR2 = 0x1c,	/* FIFO Control Register 2   */
+	ALI_CPR = 0x20,		/* Command Port Register     */
+	ALI_SPR = 0x24,		/* Status Port Register      */
+	ALI_FIFOCR3 = 0x2c,	/* FIFO Control Register 3  */
+	ALI_TTSR = 0x30,	/* Transmit Tag Slot Register */
+	ALI_RTSR = 0x34,	/* Receive Tag Slot  Register */
+	ALI_CSPSR = 0x38,	/* Command/Status Port Status Register */
+	ALI_CAS = 0x3c,		/* Codec Write Semaphore Register */
+	ALI_SPDIFCSR = 0xf8,	/* spdif channel status register  */
+	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
+};
+
+// x-status register(x:pcm in ,pcm out, mic in,)
+/* interrupts for a dma engine */
+#define DMA_INT_FIFO		(1<<4)	/* fifo under/over flow */
+#define DMA_INT_COMPLETE	(1<<3)	/* buffer read/write complete and ioc set */
+#define DMA_INT_LVI		(1<<2)	/* last valid done */
+#define DMA_INT_CELV		(1<<1)	/* last valid is current */
+#define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */	//not eqult intel
+#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
+
+/* interrupts for the whole chip */// by interrupt status register finish
+
+#define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */
+#define INT_SPDIFIN   (1<<22)
+#define INT_CODECSPDIFOUT   (1<<19)
+#define INT_MICIN   (1<<18)
+#define INT_PCMOUT   (1<<17)
+#define INT_PCMIN   (1<<16)
+#define INT_CPRAIS   (1<<7)
+#define INT_SPRAIS   (1<<5)
+#define INT_GPIO    (1<<1)
+#define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
+
+#define DRIVER_VERSION "0.02ac"
+
+/* magic numbers to protect our data structures */
+#define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */
+#define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */
+#define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */
+#define NR_HW_CH			5	//I think 5 channel
+
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define NR_AC97		2
+
+/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
+/* stream at a minimum for this card to be happy */
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
+/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
+/* values are one less than might be expected */
+static const unsigned sample_shift[] = { -1, 0, 0, 1 };
+
+#define ALI5455
+static char *card_names[] = {
+	"ALI 5455"
+};
+
+static struct pci_device_id ali_pci_tbl[] __initdata = {
+	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
+
+#ifdef CONFIG_PM
+#define PM_SUSPENDED(card) (card->pm_suspended)
+#else
+#define PM_SUSPENDED(card) (0)
+#endif
+
+/* "software" or virtual channel, an instance of opened /dev/dsp */
+struct ali_state {
+	unsigned int magic;
+	struct ali_card *card;	/* Card info */
+
+	/* single open lock mechanism, only used for recording */
+	struct semaphore open_sem;
+	wait_queue_head_t open_wait;
+
+	/* file mode */
+	mode_t open_mode;
+
+	/* virtual channel number */
+	int virt;
+
+#ifdef CONFIG_PM
+	unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
+#endif
+	struct dmabuf {
+		/* wave sample stuff */
+		unsigned int rate;
+		unsigned char fmt, enable, trigger;
+
+		/* hardware channel */
+		struct ali_channel *read_channel;
+		struct ali_channel *write_channel;
+		struct ali_channel *codec_spdifout_channel;
+		struct ali_channel *controller_spdifout_channel;
+
+		/* OSS buffer management stuff */
+		void *rawbuf;
+		dma_addr_t dma_handle;
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+
+		/* our buffer acts like a circular ring */
+		unsigned hwptr;	/* where dma last started, updated by update_ptr */
+		unsigned swptr;	/* where driver last clear/filled, updated by read/write */
+		int count;	/* bytes to be consumed or been generated by dma machine */
+		unsigned total_bytes;	/* total bytes dmaed by hardware */
+
+		unsigned error;	/* number of over/underruns */
+		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
+
+		/* redundant, but makes calculations easier */
+		/* what the hardware uses */
+		unsigned dmasize;
+		unsigned fragsize;
+		unsigned fragsamples;
+
+		/* what we tell the user to expect */
+		unsigned userfrags;
+		unsigned userfragsize;
+
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;
+		unsigned update_flag;
+		unsigned ossfragsize;
+		unsigned ossmaxfrags;
+		unsigned subdivision;
+	} dmabuf;
+};
+
+
+struct ali_card {
+	struct ali_channel channel[5];
+	unsigned int magic;
+
+	/* We keep ali5455 cards in a linked list */
+	struct ali_card *next;
+
+	/* The ali has a certain amount of cross channel interaction
+	   so we use a single per card lock */
+	spinlock_t lock;
+
+	/* PCI device stuff */
+	struct pci_dev *pci_dev;
+	u16 pci_id;
+#ifdef CONFIG_PM
+	u16 pm_suspended;
+	u32 pm_save_state[64 / sizeof(u32)];
+	int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
+#endif
+	/* soundcore stuff */
+	int dev_audio;
+
+	/* structures for abstraction of hardware facilities, codecs, banks and channels */
+	struct ac97_codec *ac97_codec[NR_AC97];
+	struct ali_state *states[NR_HW_CH];
+
+	u16 ac97_features;
+	u16 ac97_status;
+	u16 channels;
+
+	/* hardware resources */
+	unsigned long iobase;
+
+	u32 irq;
+
+	/* Function support */
+	struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
+	struct ali_channel *(*alloc_controller_spdifout_channel) (struct  ali_card *);
+	void (*free_pcm_channel) (struct ali_card *, int chan);
+
+	/* We have a *very* long init time possibly, so use this to block */
+	/* attempts to open our devices before we are ready (stops oops'es) */
+	int initializing;
+};
+
+
+static struct ali_card *devs = NULL;
+
+static int ali_open_mixdev(struct inode *inode, struct file *file);
+static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
+			    unsigned int cmd, unsigned long arg);
+static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
+static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+
+static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
+{
+	if (card->channel[1].used == 1)
+		return NULL;
+	card->channel[1].used = 1;
+	return &card->channel[1];
+}
+
+static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
+{
+	if (card->channel[0].used == 1)
+		return NULL;
+	card->channel[0].used = 1;
+	return &card->channel[0];
+}
+
+static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
+{
+	if (card->channel[2].used == 1)
+		return NULL;
+	card->channel[2].used = 1;
+	return &card->channel[2];
+}
+
+static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
+{
+	if (card->channel[3].used == 1)
+		return NULL;
+	card->channel[3].used = 1;
+	return &card->channel[3];
+}
+
+static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
+{
+	if (card->channel[4].used == 1)
+		return NULL;
+	card->channel[4].used = 1;
+	return &card->channel[4];
+}
+static void ali_free_pcm_channel(struct ali_card *card, int channel)
+{
+	card->channel[channel].used = 0;
+}
+
+
+//add support  codec spdif out 
+static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
+{
+	unsigned long id = 0L;
+
+	id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
+	id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
+	switch (id) {
+	case 0x41445361:	/* AD1886 */
+		if (rate == 48000) {
+			return 1;
+		}
+		break;
+	case 0x414c4720:	/* ALC650 */
+		if (rate == 48000) {
+			return 1;
+		}
+		break;
+	default:		/* all other codecs, until we know otherwiae */
+		if (rate == 48000 || rate == 44100 || rate == 32000) {
+			return 1;
+		}
+		break;
+	}
+	return (0);
+}
+
+/* ali_set_spdif_output
+ * 
+ *  Configure the S/PDIF output transmitter. When we turn on
+ *  S/PDIF, we turn off the analog output. This may not be
+ *  the right thing to do.
+ *
+ *  Assumptions:
+ *     The DSP sample rate must already be set to a supported
+ *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
+ */
+static void ali_set_spdif_output(struct ali_state *state, int slots,
+				 int rate)
+{
+	int vol;
+	int aud_reg;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 4)) {
+		state->card->ac97_status &= ~SPDIF_ON;
+	} else {
+		if (slots == -1) {	/* Turn off S/PDIF */
+			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+
+			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */
+			if (!(state->card->ac97_status & VOL_MUTED)) {
+				aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
+					     (aud_reg & ~VOL_MUTED));
+			}
+			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
+			return;
+		}
+
+		vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+		state->card->ac97_status = vol & VOL_MUTED;
+
+		/* Set S/PDIF transmitter sample rate */
+		aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+		switch (rate) {
+		case 32000:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
+			break;
+		case 44100:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
+			break;
+		case 48000:
+			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
+			break;
+		default:
+			/* turn off S/PDIF */
+			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+			state->card->ac97_status &= ~SPDIF_ON;
+			return;
+		}
+
+		ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
+
+		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
+		ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+
+		aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
+		aud_reg |= 0x0002;
+		ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
+		udelay(1);
+
+		state->card->ac97_status |= SPDIF_ON;
+
+		/* Check to make sure the configuration is valid */
+		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+		if (!(aud_reg & 0x0400)) {
+			/* turn off S/PDIF */
+			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+			state->card->ac97_status &= ~SPDIF_ON;
+			return;
+		}
+		if (codec_independent_spdif_locked > 0) {
+			aud_reg = ali_ac97_get(codec, 0x6a);
+			ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
+		}
+		/* Mute the analog output */
+		/* Should this only mute the PCM volume??? */
+	}
+}
+
+/* ali_set_dac_channels
+ *
+ *  Configure the codec's multi-channel DACs
+ *
+ *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
+ *
+ *  What about the ICH? We currently configure it using the
+ *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
+ *  does that imply that we want the ICH set to support
+ *  these channels?
+ *  
+ *  TODO:
+ *    vailidate that the codec really supports these DACs
+ *    before turning them on. 
+ */
+static void ali_set_dac_channels(struct ali_state *state, int channel)
+{
+	int aud_reg;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
+	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
+	state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
+
+	switch (channel) {
+	case 2:		/* always enabled */
+		break;
+	case 4:
+		aud_reg &= ~AC97_EA_PRJ;
+		state->card->ac97_status |= SURR_ON;
+		break;
+	case 6:
+		aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
+		state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
+		break;
+	default:
+		break;
+	}
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+
+}
+
+/* set playback sample rate */
+static unsigned int ali_set_dac_rate(struct ali_state *state,
+				     unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 new_rate;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	/*
+	 *      Adjust for misclocked crap
+	 */
+
+	rate = (rate * clocking) / 48000;
+
+	if (strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000) / clocking;
+	}
+
+	new_rate = ac97_set_dac_rate(codec, rate);
+	if (new_rate != rate) {
+		dmabuf->rate = (new_rate * 48000) / clocking;
+	}
+	rate = new_rate;
+	return dmabuf->rate;
+}
+
+/* set recording sample rate */
+static unsigned int ali_set_adc_rate(struct ali_state *state,
+				     unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 new_rate;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	/*
+	 *      Adjust for misclocked crap
+	 */
+
+	rate = (rate * clocking) / 48000;
+	if (strict_clocking && rate < 8000) {
+		rate = 8000;
+		dmabuf->rate = (rate * 48000) / clocking;
+	}
+
+	new_rate = ac97_set_adc_rate(codec, rate);
+
+	if (new_rate != rate) {
+		dmabuf->rate = (new_rate * 48000) / clocking;
+		rate = new_rate;
+	}
+	return dmabuf->rate;
+}
+
+/* set codec independent spdifout sample rate */
+static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
+					       unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (!(state->card->ac97_features & 0x0001)) {
+		dmabuf->rate = clocking;
+		return clocking;
+	}
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	dmabuf->rate = rate;
+
+	return dmabuf->rate;
+}
+
+/* set  controller independent spdif out function sample rate */
+static void ali_set_spdifout_rate(struct ali_state *state,
+				  unsigned int rate)
+{
+	unsigned char ch_st_sel;
+	unsigned short status_rate;
+
+	switch (rate) {
+	case 44100:
+		status_rate = 0;
+		break;
+	case 32000:
+		status_rate = 0x300;
+		break;
+	case 48000:
+	default:
+		status_rate = 0x200;
+		break;
+	}
+
+	ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS;	//select spdif_out
+
+	ch_st_sel |= 0x80;	//select right
+	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+	outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
+
+	ch_st_sel &= (~0x80);	//select left
+	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
+	outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
+}
+
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+   called with spinlock held! */
+
+static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int civ, offset, port, port_picb;
+	unsigned int data;
+
+	if (!dmabuf->enable)
+		return 0;
+
+	if (rec == 1)
+		port = state->card->iobase + dmabuf->read_channel->port;
+	else if (rec == 2)
+		port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
+	else if (rec == 3)
+		port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
+	else
+		port = state->card->iobase + dmabuf->write_channel->port;
+
+	port_picb = port + OFF_PICB;
+
+	do {
+		civ = inb(port + OFF_CIV) & 31;
+		offset = inw(port_picb);
+		/* Must have a delay here! */
+		if (offset == 0)
+			udelay(1);
+
+		/* Reread both registers and make sure that that total
+		 * offset from the first reading to the second is 0.
+		 * There is an issue with SiS hardware where it will count
+		 * picb down to 0, then update civ to the next value,
+		 * then set the new picb to fragsize bytes.  We can catch
+		 * it between the civ update and the picb update, making
+		 * it look as though we are 1 fragsize ahead of where we
+		 * are.  The next to we get the address though, it will
+		 * be back in thdelay is more than long enough
+		 * that we won't have to worry about the chip still being
+		 * out of sync with reality ;-)
+		 */
+	} while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
+
+	data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
+	if (inw(port_picb) == 0)
+		data -= 2048;
+
+	return data;
+}
+
+/* Stop recording (lock held) */
+static inline void __stop_adc(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	dmabuf->enable &= ~ADC_RUNNING;
+
+	outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
+	udelay(1);
+
+	outb(0, card->iobase + PI_CR);
+	while (inb(card->iobase + PI_CR) != 0);
+
+	// now clear any latent interrupt bits (like the halt bit)
+	outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
+	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
+}
+
+static void stop_adc(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_adc(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
+	    && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+		dmabuf->enable |= ADC_RUNNING;
+		outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
+		if (state->card->channel[0].used == 1)
+			outl(1, state->card->iobase + ALI_DMACR);	// DMA CONTROL REGISTRER
+		udelay(100);
+		if (state->card->channel[2].used == 1)
+			outl((1 << 2), state->card->iobase + ALI_DMACR);	//DMA CONTROL REGISTER
+		udelay(100);
+	}
+}
+
+static void start_adc(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop playback (lock held) */
+static inline void __stop_dac(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	dmabuf->enable &= ~DAC_RUNNING;
+	outl(0x00020000, card->iobase + 0x08);
+	outb(0, card->iobase + PO_CR);
+	while (inb(card->iobase + PO_CR) != 0)
+		cpu_relax();
+
+	outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
+
+	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
+}
+
+static void stop_dac(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_dac(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+		dmabuf->enable |= DAC_RUNNING;
+		outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
+		outl((1 << 1), state->card->iobase + 0x08);	//dma control register
+	}
+}
+
+static void start_dac(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__start_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop codec and controller spdif out  (lock held) */
+static inline void __stop_spdifout(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_card *card = state->card;
+
+	if (codec_independent_spdif_locked > 0) {
+		dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
+		outl((1 << 19), card->iobase + 0x08);
+		outb(0, card->iobase + CODECSPDIFOUT_CR);
+
+		while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
+			cpu_relax();
+
+		outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
+		outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
+			outl((1 << 23), card->iobase + 0x08);
+			outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
+			while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
+				cpu_relax();
+			outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
+			outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
+		}
+	}
+}
+
+static void stop_spdifout(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_spdifout(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void __start_spdifout(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
+	    (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+		if (codec_independent_spdif_locked > 0) {
+			dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
+			outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
+			outl((1 << 3), state->card->iobase + 0x08);	//dma control register
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
+				outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
+				outl((1 << 7), state->card->iobase + 0x08);	//dma control register
+			}
+		}
+	}
+}
+
+static void start_spdifout(struct ali_state *state)
+{
+	struct ali_card *card = state->card;
+	unsigned long flags;
+	spin_lock_irqsave(&card->lock, flags);
+	__start_spdifout(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+/* allocate DMA buffer, playback , recording,spdif out  buffer should be allocated seperately */
+static int alloc_dmabuf(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	void *rawbuf = NULL;
+	int order, size;
+	struct page *page, *pend;
+
+	/* If we don't have any oss frag params, then use our default ones */
+	if (dmabuf->ossmaxfrags == 0)
+		dmabuf->ossmaxfrags = 4;
+	if (dmabuf->ossfragsize == 0)
+		dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
+	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+
+	if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
+		return 0;
+	/* alloc enough to satisfy the oss params */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+		if ((PAGE_SIZE << order) > size)
+			continue;
+		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
+						   PAGE_SIZE << order,
+						   &dmabuf->dma_handle)))
+			break;
+	}
+	if (!rawbuf)
+		return -ENOMEM;
+
+	dmabuf->ready = dmabuf->mapped = 0;
+	dmabuf->rawbuf = rawbuf;
+	dmabuf->buforder = order;
+
+	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
+	for (page = virt_to_page(rawbuf); page <= pend; page++)
+		mem_map_reserve(page);
+	return 0;
+}
+
+/* free DMA buffer */
+static void dealloc_dmabuf(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct page *page, *pend;
+
+	if (dmabuf->rawbuf) {
+		/* undo marking the pages as reserved */
+		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
+			mem_map_unreserve(page);
+		pci_free_consistent(state->card->pci_dev,
+				    PAGE_SIZE << dmabuf->buforder,
+				    dmabuf->rawbuf, dmabuf->dma_handle);
+	}
+	dmabuf->rawbuf = NULL;
+	dmabuf->mapped = dmabuf->ready = 0;
+}
+
+static int prog_dmabuf(struct ali_state *state, unsigned rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct ali_channel *c = NULL;
+	struct sg_item *sg;
+	unsigned long flags;
+	int ret;
+	unsigned fragint;
+	int i;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	if (dmabuf->enable & DAC_RUNNING)
+		__stop_dac(state);
+	if (dmabuf->enable & ADC_RUNNING)
+		__stop_adc(state);
+	if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+		__stop_spdifout(state);
+	if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+		__stop_spdifout(state);
+
+	dmabuf->total_bytes = 0;
+	dmabuf->count = dmabuf->error = 0;
+	dmabuf->swptr = dmabuf->hwptr = 0;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* allocate DMA buffer, let alloc_dmabuf determine if we are already
+	 * allocated well enough or if we should replace the current buffer
+	 * (assuming one is already allocated, if it isn't, then allocate it).
+	 */
+	if ((ret = alloc_dmabuf(state)))
+		return ret;
+
+	/* FIXME: figure out all this OSS fragment stuff */
+	/* I did, it now does what it should according to the OSS API.  DL */
+	/* We may not have realloced our dmabuf, but the fragment size to
+	 * fragment number ratio may have changed, so go ahead and reprogram
+	 * things
+	 */
+
+	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
+	dmabuf->numfrag = SG_LEN;
+	dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
+	dmabuf->fragsamples = dmabuf->fragsize >> 1;
+	dmabuf->userfragsize = dmabuf->ossfragsize;
+	dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
+
+	memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
+
+	if (dmabuf->ossmaxfrags == 4) {
+		fragint = 8;
+		dmabuf->fragshift = 2;
+	} else if (dmabuf->ossmaxfrags == 8) {
+		fragint = 4;
+		dmabuf->fragshift = 3;
+	} else if (dmabuf->ossmaxfrags == 16) {
+		fragint = 2;
+		dmabuf->fragshift = 4;
+	} else {
+		fragint = 1;
+		dmabuf->fragshift = 5;
+	}
+	/*
+	 *      Now set up the ring 
+	 */
+
+	if (rec == 1)
+		c = dmabuf->read_channel;
+	else if (rec == 2)
+		c = dmabuf->codec_spdifout_channel;
+	else if (rec == 3)
+		c = dmabuf->controller_spdifout_channel;
+	else if (rec == 0)
+		c = dmabuf->write_channel;
+	if (c != NULL) {
+		sg = &c->sg[0];
+		/*
+		 *      Load up 32 sg entries and take an interrupt at half
+		 *      way (we might want more interrupts later..) 
+		 */
+		for (i = 0; i < dmabuf->numfrag; i++) {
+			sg->busaddr =
+			    virt_to_bus(dmabuf->rawbuf +
+					dmabuf->fragsize * i);
+			// the card will always be doing 16bit stereo
+			sg->control = dmabuf->fragsamples;
+			sg->control |= CON_BUFPAD;	//I modify
+			// set us up to get IOC interrupts as often as needed to
+			// satisfy numfrag requirements, no more
+			if (((i + 1) % fragint) == 0) {
+				sg->control |= CON_IOC;
+			}
+			sg++;
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
+		outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
+		outb(0, state->card->iobase + c->port + OFF_CIV);
+		outb(0, state->card->iobase + c->port + OFF_LVI);
+		spin_unlock_irqrestore(&state->card->lock, flags);
+	}
+	/* set the ready flag for the dma buffer */
+	dmabuf->ready = 1;
+	return 0;
+}
+
+static void __ali_update_lvi(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int x, port;
+	port = state->card->iobase;
+	if (rec == 1)
+		port += dmabuf->read_channel->port;
+	else if (rec == 2)
+		port += dmabuf->codec_spdifout_channel->port;
+	else if (rec == 3)
+		port += dmabuf->controller_spdifout_channel->port;
+	else if (rec == 0)
+		port += dmabuf->write_channel->port;
+	/* if we are currently stopped, then our CIV is actually set to our
+	 * *last* sg segment and we are ready to wrap to the next.  However,
+	 * if we set our LVI to the last sg segment, then it won't wrap to
+	 * the next sg segment, it won't even get a start.  So, instead, when
+	 * we are stopped, we set both the LVI value and also we increment
+	 * the CIV value to the next sg segment to be played so that when
+	 * we call start_{dac,adc}, things will operate properly
+	 */
+	if (!dmabuf->enable && dmabuf->ready) {
+		if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+			__start_adc(state);
+			while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+				cpu_relax();
+		} else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+			__start_dac(state);
+			while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+				cpu_relax();
+		} else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+			if (codec_independent_spdif_locked > 0) {
+				// outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
+				outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+				__start_spdifout(state);
+				while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+					cpu_relax();
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
+					__start_spdifout(state);
+					while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
+						cpu_relax();
+				}
+			}
+		}
+	}
+
+	/* swptr - 1 is the tail of our transfer */
+	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
+	x /= dmabuf->fragsize;
+	outb(x, port + OFF_LVI);
+}
+
+static void ali_update_lvi(struct ali_state *state, int rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	if (!dmabuf->ready)
+		return;
+	spin_lock_irqsave(&state->card->lock, flags);
+	__ali_update_lvi(state, rec);
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+static void ali_update_ptr(struct ali_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned hwptr;
+	int diff;
+	
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 1);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a read */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count > dmabuf->userfragsize)
+			wake_up(&dmabuf->wait);
+	}
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 0);
+		diff =
+		    (dmabuf->dmasize + hwptr -
+		     dmabuf->hwptr) % dmabuf->dmasize;
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
+				     			inb(state->card->iobase + PO_CIV) & 31,
+				     			inb(state->card->iobase + PO_LVI) & 31, 
+							dmabuf->hwptr,
+							dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+		    	wake_up(&dmabuf->wait);
+	}
+
+	/* error handling and process wake up for CODEC SPDIF OUT */
+	if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 2);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
+				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
+				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", 
+				        inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
+					inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
+					dmabuf->hwptr, dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+			wake_up(&dmabuf->wait);
+	}
+	/* error handling and process wake up for CONTROLLER SPDIF OUT */
+	if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+		/* update hardware pointer */
+		hwptr = ali_get_dma_addr(state, 3);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count -= diff;
+		if (dmabuf->count < 0) {
+			/* buffer underrun or buffer overrun */
+			/* this is normal for the end of a write */
+			/* only give an error if we went past the */
+			/* last valid sg entry */
+			if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
+				printk(KERN_WARNING
+				       "ali_audio: DMA overrun on write\n");
+				printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
+					"count %d\n",
+				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
+				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
+				     		dmabuf->hwptr, dmabuf->count);
+				dmabuf->error++;
+			}
+		}
+		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
+			wake_up(&dmabuf->wait);
+	}
+}
+
+static inline int ali_get_free_write_space(struct
+					   ali_state
+					   *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int free;
+	ali_update_ptr(state);
+	// catch underruns during playback
+	if (dmabuf->count < 0) {
+		dmabuf->count = 0;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	free = dmabuf->dmasize - dmabuf->count;
+	free -= (dmabuf->hwptr % dmabuf->fragsize);
+	if (free < 0)
+		return (0);
+	return (free);
+}
+
+static inline int ali_get_available_read_data(struct
+					      ali_state
+					      *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int avail;
+	ali_update_ptr(state);
+	// catch overruns during record
+	if (dmabuf->count > dmabuf->dmasize) {
+		dmabuf->count = dmabuf->dmasize;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	avail = dmabuf->count;
+	avail -= (dmabuf->hwptr % dmabuf->fragsize);
+	if (avail < 0)
+		return (0);
+	return (avail);
+}
+
+static int drain_dac(struct ali_state *state, int signals_allowed)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+	if (!dmabuf->ready)
+		return 0;
+	if (dmabuf->mapped) {
+		stop_dac(state);
+		return 0;
+	}
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		if (count <= 0)
+			break;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if (!dmabuf->enable) {
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
+			ali_update_lvi(state, 0);
+		}
+		if (signal_pending(current) && signals_allowed) {
+			break;
+		}
+
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+			printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n");
+			count = 0;
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if (count > 0 && signal_pending(current) && signals_allowed)
+		return -ERESTARTSYS;
+	stop_dac(state);
+	return 0;
+}
+
+
+static int drain_spdifout(struct ali_state *state, int signals_allowed)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+	if (!dmabuf->ready)
+		return 0;
+	if (dmabuf->mapped) {
+		stop_spdifout(state);
+		return 0;
+	}
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		if (count <= 0)
+			break;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if (!dmabuf->enable) {
+			if (codec_independent_spdif_locked > 0) {
+				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+				ali_update_lvi(state, 2);
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+					ali_update_lvi(state, 3);
+				}
+			}
+		}
+		if (signal_pending(current) && signals_allowed) {
+			break;
+		}
+
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+			printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n");
+			count = 0;
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if (count > 0 && signal_pending(current) && signals_allowed)
+		return -ERESTARTSYS;
+	stop_spdifout(state);
+	return 0;
+}
+
+static void ali_channel_interrupt(struct ali_card *card)
+{
+	int i, count;
+	
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		struct ali_channel *c = NULL;
+		struct dmabuf *dmabuf;
+		unsigned long port = card->iobase;
+		u16 status;
+		if (!state)
+			continue;
+		if (!state->dmabuf.ready)
+			continue;
+		dmabuf = &state->dmabuf;
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+				c = dmabuf->codec_spdifout_channel;
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					c = dmabuf->controller_spdifout_channel;
+			} else {
+				if (dmabuf->enable & DAC_RUNNING) {
+					c = dmabuf->write_channel;
+				} else if (dmabuf->enable & ADC_RUNNING) {
+					c = dmabuf->read_channel;
+				} else
+					continue;
+			}
+		}
+		port += c->port;
+
+		status = inw(port + OFF_SR);
+
+		if (status & DMA_INT_COMPLETE) {
+			/* only wake_up() waiters if this interrupt signals
+			 * us being beyond a userfragsize of data open or
+			 * available, and ali_update_ptr() does that for
+			 * us
+			 */
+			ali_update_ptr(state);
+		}
+
+		if (status & DMA_INT_LVI) {
+			ali_update_ptr(state);
+			wake_up(&dmabuf->wait);
+
+			if (dmabuf->enable & DAC_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & ADC_RUNNING)
+				count = dmabuf->dmasize - dmabuf->count;
+			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else count = 0;
+
+			if (count > 0) {
+				if (dmabuf->enable & DAC_RUNNING)
+					outl((1 << 1), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+						outl((1 << 3), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					outl((1 << 7), state->card->iobase + ALI_DMACR);
+			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				dmabuf->enable = 0;
+				wake_up(&dmabuf->wait);
+			}
+
+		}
+		if (!(status & DMA_INT_DCH)) {
+			ali_update_ptr(state);
+			wake_up(&dmabuf->wait);
+			if (dmabuf->enable & DAC_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & ADC_RUNNING)
+				count = dmabuf->dmasize - dmabuf->count;
+			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+				count = dmabuf->count;
+			else
+				count = 0;
+
+			if (count > 0) {
+				if (dmabuf->enable & DAC_RUNNING)
+					outl((1 << 1), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					outl((1 << 3), state->card->iobase + ALI_DMACR);
+				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					outl((1 << 7), state->card->iobase + ALI_DMACR);
+			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
+					__stop_spdifout(state);
+				dmabuf->enable = 0;
+				wake_up(&dmabuf->wait);
+			}
+		}
+		outw(status & DMA_INT_MASK, port + OFF_SR);
+	}
+}
+
+static void ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ali_card *card = (struct ali_card *) dev_id;
+	u32 status;
+	u16 status2;
+
+	spin_lock(&card->lock);
+	status = inl(card->iobase + ALI_INTERRUPTSR);
+	if (!(status & INT_MASK)) {
+		spin_unlock(&card->lock);
+		return;		/* not for us */
+	}
+
+	if (codec_independent_spdif_locked > 0) {
+		if (globel == 0) {
+			globel += 1;
+			status2 = inw(card->iobase + 0x76);
+			outw(status2 | 0x000c, card->iobase + 0x76);
+		} else {
+			if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+				ali_channel_interrupt(card);
+		}
+	} else {
+		if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+			ali_channel_interrupt(card);
+	}
+
+	/* clear 'em */
+	outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
+	spin_unlock(&card->lock);
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is
+   waiting to be copied to the user's buffer.  It is filled by the dma
+   machine and drained by this loop. */
+
+static ssize_t ali_read(struct file *file, char *buffer,
+			size_t count, loff_t * ppos)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state ? state->card : 0;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned int swptr;
+	int cnt;
+	DECLARE_WAITQUEUE(waita, current);
+#ifdef DEBUG2
+	printk("ali_audio: ali_read called, count = %d\n", count);
+#endif
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (dmabuf->enable & DAC_RUNNING)
+		return -ENODEV;
+	if (!dmabuf->read_channel) {
+		dmabuf->ready = 0;
+		dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
+		if (!dmabuf->read_channel) {
+			return -EBUSY;
+		}
+	}
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	add_wait_queue(&dmabuf->wait, &waita);
+	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
+		swptr = dmabuf->swptr;
+		cnt = ali_get_available_read_data(state);
+		// this is to make the copy_to_user simpler below
+		if (cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
+		spin_unlock_irqrestore(&card->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/*
+			 * Don't let us deadlock.  The ADC won't start if
+			 * dmabuf->trigger isn't set.  A call to SETTRIGGER
+			 * could have turned it off after we set it to on
+			 * previously.
+			 */
+			dmabuf->trigger = PCM_ENABLE_INPUT;
+			/*
+			 * This does three things.  Updates LVI to be correct,
+			 * makes sure the ADC is running, and updates the
+			 * hwptr.
+			 */
+			ali_update_lvi(state, 1);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				goto done;
+			}
+			/* Set the timeout to how long it would take to fill
+			 * two of our buffers.  If we haven't been woke up
+			 * by then, then we know something is wrong.
+			 */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+			    
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer overrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
+				printk(KERN_ERR
+				       "ali_audio: recording schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize,
+				       dmabuf->count, dmabuf->hwptr,
+				       dmabuf->swptr);
+				/* a buffer overrun, we delay the recovery until next time the
+				   while loop begin and we REALLY have space to record */
+			}
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				goto done;
+			}
+			continue;
+		}
+
+		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			goto done;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+		spin_lock_irqsave(&card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			continue;
+		}
+		dmabuf->swptr = swptr;
+		dmabuf->count -= cnt;
+		spin_unlock_irqrestore(&card->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+	}
+done:
+	ali_update_lvi(state, 1);
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &waita);
+	return ret;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
+static ssize_t ali_write(struct file *file,
+			 const char *buffer, size_t count, loff_t * ppos)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state ? state->card : 0;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned int swptr = 0;
+	int cnt, x;
+	DECLARE_WAITQUEUE(waita, current);
+#ifdef DEBUG2
+	printk("ali_audio: ali_write called, count = %d\n", count);
+#endif
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (dmabuf->enable & ADC_RUNNING)
+		return -ENODEV;
+	if (codec_independent_spdif_locked > 0) {
+		if (!dmabuf->codec_spdifout_channel) {
+			dmabuf->ready = 0;
+			dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
+			if (!dmabuf->codec_spdifout_channel)
+				return -EBUSY;
+		}
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			if (!dmabuf->controller_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
+				if (!dmabuf->controller_spdifout_channel)
+					return -EBUSY;
+			}
+		} else {
+			if (!dmabuf->write_channel) {
+				dmabuf->ready = 0;
+				dmabuf->write_channel =
+				    card->alloc_pcm_channel(card);
+				if (!dmabuf->write_channel)
+					return -EBUSY;
+			}
+		}
+	}
+
+	if (codec_independent_spdif_locked > 0) {
+		if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+			return ret;
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+				return ret;
+		} else {
+
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+				return ret;
+		}
+	}
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	add_wait_queue(&dmabuf->wait, &waita);
+	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			continue;
+		}
+
+		swptr = dmabuf->swptr;
+		cnt = ali_get_free_write_space(state);
+		/* Bound the maximum size to how much we can copy to the
+		 * dma buffer before we hit the end.  If we have more to
+		 * copy then it will get done in a second pass of this
+		 * loop starting from the beginning of the buffer.
+		 */
+		if (cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG2
+		printk(KERN_INFO
+		       "ali_audio: ali_write: %d bytes available space\n",
+		       cnt);
+#endif
+		if (cnt > count)
+			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			// There is data waiting to be played
+			/*
+			 * Force the trigger setting since we would
+			 * deadlock with it set any other way
+			 */
+			if (codec_independent_spdif_locked > 0) {
+				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+				ali_update_lvi(state, 2);
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
+					ali_update_lvi(state, 3);
+				} else {
+
+					dmabuf->trigger = PCM_ENABLE_OUTPUT;
+					ali_update_lvi(state, 0);
+				}
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				goto ret;
+			}
+			/* Not strictly correct but works */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer underrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			   
+			/* FIXME - do timeout handling here !! */
+
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				goto ret;
+			}
+			continue;
+		}
+		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			goto ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (PM_SUSPENDED(card)) {
+			spin_unlock_irqrestore(&card->lock, flags);
+			continue;
+		}
+
+		dmabuf->swptr = swptr;
+		dmabuf->count += cnt;
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+	}
+	if (swptr % dmabuf->fragsize) {
+		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
+		memset(dmabuf->rawbuf + swptr, '\0', x);
+	}
+ret:
+	if (codec_independent_spdif_locked > 0) {
+		ali_update_lvi(state, 2);
+	} else {
+		if (controller_independent_spdif_locked > 0) {
+			ali_update_lvi(state, 3);
+		} else {
+			ali_update_lvi(state, 0);
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dmabuf->wait, &waita);
+	return ret;
+}
+
+/* No kernel lock - we have our own spinlock */
+static unsigned int ali_poll(struct file *file, struct poll_table_struct
+			     *wait)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned int mask = 0;
+	if (!dmabuf->ready)
+		return 0;
+	poll_wait(file, &dmabuf->wait, wait);
+	spin_lock_irqsave(&state->card->lock, flags);
+	ali_update_ptr(state);
+	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
+		if (dmabuf->count >= (signed) dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE  && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
+		if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+	return mask;
+}
+
+static int ali_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int ret = -EINVAL;
+	unsigned long size;
+	lock_kernel();
+	if (vma->vm_flags & VM_WRITE) {
+		if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	if (vma->vm_flags & VM_READ) {
+		if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	if ((ret = prog_dmabuf(state, 0)) != 0)
+		goto out;
+	ret = -EINVAL;
+	if (vma->vm_pgoff != 0)
+		goto out;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << dmabuf->buforder))
+		goto out;
+	ret = -EAGAIN;
+	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot))
+		goto out;
+	dmabuf->mapped = 1;
+	dmabuf->trigger = 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_channel *c = NULL;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	audio_buf_info abinfo;
+	count_info cinfo;
+	unsigned int i_scr;
+	int val = 0, ret;
+	struct ac97_codec *codec = state->card->ac97_codec[0];
+#ifdef DEBUG
+	printk("ali_audio: ali_ioctl, arg=0x%x, cmd=",
+	       arg ? *(int *) arg : 0);
+#endif
+	switch (cmd) {
+	case OSS_GETVERSION:
+#ifdef DEBUG
+		printk("OSS_GETVERSION\n");
+#endif
+		return put_user(SOUND_VERSION, (int *) arg);
+	case SNDCTL_DSP_RESET:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_RESET\n");
+#endif
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->enable == DAC_RUNNING) {
+			c = dmabuf->write_channel;
+			__stop_dac(state);
+		}
+		if (dmabuf->enable == ADC_RUNNING) {
+			c = dmabuf->read_channel;
+			__stop_adc(state);
+		}
+		if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+			c = dmabuf->codec_spdifout_channel;
+			__stop_spdifout(state);
+		}
+		if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+			c = dmabuf->controller_spdifout_channel;
+			__stop_spdifout(state);
+		}
+		if (c != NULL) {
+			outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
+			outl(virt_to_bus(&c->sg[0]),
+			     state->card->iobase + c->port + OFF_BDBAR);
+			outb(0, state->card->iobase + c->port + OFF_CIV);
+			outb(0, state->card->iobase + c->port + OFF_LVI);
+		}
+
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		synchronize_irq();
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
+		return 0;
+	case SNDCTL_DSP_SYNC:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SYNC\n");
+#endif
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
+			    || file->f_flags & O_NONBLOCK)
+				return 0;
+			if ((val = drain_spdifout(state, 1)))
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->enable !=
+				    CONTROLLER_SPDIFOUT_RUNNING
+				    || file->f_flags & O_NONBLOCK)
+					return 0;
+				if ((val = drain_spdifout(state, 1)))
+					return val;
+			} else {
+				if (dmabuf->enable != DAC_RUNNING
+				    || file->f_flags & O_NONBLOCK)
+					return 0;
+				if ((val = drain_dac(state, 1)))
+					return val;
+			}
+		}
+		dmabuf->total_bytes = 0;
+		return 0;
+	case SNDCTL_DSP_SPEED:	/* set smaple rate */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SPEED\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				if ((state->card->ac97_status & SPDIF_ON)) {	/* S/PDIF Enabled */
+					/* RELTEK ALC650 only support 48000, need to check that */
+					if (ali_valid_spdif_rate(codec, val)) {
+						if (codec_independent_spdif_locked > 0) {
+							ali_set_spdif_output(state, -1, 0);
+							stop_spdifout(state);
+							dmabuf->ready = 0;
+							/* I add test codec independent spdif out */
+							spin_lock_irqsave(&state->card->lock, flags);
+							ali_set_codecspdifout_rate(state, val);	// I modified
+							spin_unlock_irqrestore(&state->card->lock, flags);
+							/* Set S/PDIF transmitter rate. */
+							i_scr = inl(state->card->iobase + ALI_SCR);
+							if ((i_scr & 0x00300000) == 0x00100000) {
+								ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+							} else {
+								if ((i_scr&0x00300000)  == 0x00200000)
+								{
+									ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+								} else {
+									if ((i_scr & 0x00300000) == 0x00300000) {
+										ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+									} else {
+										ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+									}
+								}
+							}
+
+							if (!(state->card->ac97_status & SPDIF_ON)) {
+								val = dmabuf->rate;
+							}
+						} else {
+							if (controller_independent_spdif_locked > 0) 
+							{
+								stop_spdifout(state);
+								dmabuf->ready = 0;
+								spin_lock_irqsave(&state->card->lock, flags);
+								ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+								spin_unlock_irqrestore(&state->card->lock, flags);
+							} else {
+								/* Set DAC rate */
+								ali_set_spdif_output(state, -1, 0);
+								stop_dac(state);
+								dmabuf->ready = 0;
+								spin_lock_irqsave(&state->card->lock, flags);
+								ali_set_dac_rate(state, val);
+								spin_unlock_irqrestore(&state->card->lock, flags);
+								/* Set S/PDIF transmitter rate. */
+								ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val);
+								if (!(state->card->ac97_status & SPDIF_ON))
+								{
+									val = dmabuf->rate;
+								}
+							}
+						}
+					} else {	/* Not a valid rate for S/PDIF, ignore it */
+						val = dmabuf->rate;
+					}
+				} else {
+					stop_dac(state);
+					dmabuf->ready = 0;
+					spin_lock_irqsave(&state->card->lock, flags);
+					ali_set_dac_rate(state, val);
+					spin_unlock_irqrestore(&state->card->lock, flags);
+				}
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_set_adc_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+		}
+		return put_user(dmabuf->rate, (int *) arg);
+	case SNDCTL_DSP_STEREO:	/* set stereo or mono channel */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_STEREO\n");
+#endif
+		if (dmabuf->enable & DAC_RUNNING) {
+			stop_dac(state);
+		}
+		if (dmabuf->enable & ADC_RUNNING) {
+			stop_adc(state);
+		}
+		if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		return put_user(1, (int *) arg);
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if (codec_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
+					return val;
+			} else {
+				if (controller_independent_spdif_locked > 0) {
+					if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
+						return val;
+				} else {
+					if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
+						return val;
+				}
+			}
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
+				return val;
+		}
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
+#endif
+		return put_user(dmabuf->userfragsize, (int *) arg);
+	case SNDCTL_DSP_GETFMTS:	/* Returns a mask of supported sample format */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETFMTS\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_SETFMT:	/* Select sample format */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFMT\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_CHANNELS:	// add support 4,6 channel 
+#ifdef DEBUG
+		printk("SNDCTL_DSP_CHANNELS\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val > 0) {
+			if (dmabuf->enable & DAC_RUNNING) {
+				stop_dac(state);
+			}
+			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
+				stop_spdifout(state);
+			}
+			if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
+				stop_spdifout(state);
+			}
+			if (dmabuf->enable & ADC_RUNNING) {
+				stop_adc(state);
+			}
+		} else {
+			return put_user(state->card->channels, (int *) arg);
+		}
+
+		i_scr = inl(state->card->iobase + ALI_SCR);
+		/* Current # of channels enabled */
+		if (i_scr & 0x00000100)
+			ret = 4;
+		else if (i_scr & 0x00000200)
+			ret = 6;
+		else
+			ret = 2;
+		switch (val) {
+		case 2:	/* 2 channels is always supported */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
+			} else
+				outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
+			/* Do we need to change mixer settings????  */
+			break;
+		case 4:	/* Supported on some chipsets, better check first */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
+			} else
+				outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
+			break;
+		case 6:	/* Supported on some chipsets, better check first */
+			if (codec_independent_spdif_locked > 0) {
+				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
+			} else
+				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
+			break;
+		default:	/* nothing else is ever supported by the chipset */
+			val = ret;
+			break;
+		}
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_POST:	/* the user has sent all data and is notifying us */
+		/* we update the swptr to the end of the last sg segment then return */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_POST\n");
+#endif
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
+				return 0;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
+					return 0;
+			} else {
+				if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
+					return 0;
+			}
+		}
+		if ((dmabuf->swptr % dmabuf->fragsize) != 0) {
+			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
+			dmabuf->swptr += val;
+			dmabuf->count += val;
+		}
+		return 0;
+	case SNDCTL_DSP_SUBDIVIDE:
+		if (dmabuf->subdivision)
+			return -EINVAL;
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
+#endif
+		dmabuf->subdivision = val;
+		dmabuf->ready = 0;
+		return 0;
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		dmabuf->ossfragsize = 1 << (val & 0xffff);
+		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+			return -EINVAL;
+		/*
+		 * Bound the frag size into our allowed range of 256 - 4096
+		 */
+		if (dmabuf->ossfragsize < 256)
+			dmabuf->ossfragsize = 256;
+		else if (dmabuf->ossfragsize > 4096)
+			dmabuf->ossfragsize = 4096;
+		/*
+		 * The numfrags could be something reasonable, or it could
+		 * be 0xffff meaning "Give me as much as possible".  So,
+		 * we check the numfrags * fragsize doesn't exceed our
+		 * 64k buffer limit, nor is it less than our 8k minimum.
+		 * If it fails either one of these checks, then adjust the
+		 * number of fragments, not the size of them.  It's OK if
+		 * our number of fragments doesn't equal 32 or anything
+		 * like our hardware based number now since we are using
+		 * a different frag count for the hardware.  Before we get
+		 * into this though, bound the maxfrags to avoid overflow
+		 * issues.  A reasonable bound would be 64k / 256 since our
+		 * maximum buffer size is 64k and our minimum frag size is
+		 * 256.  On the other end, our minimum buffer size is 8k and
+		 * our maximum frag size is 4k, so the lower bound should
+		 * be 2.
+		 */
+		if (dmabuf->ossmaxfrags > 256)
+			dmabuf->ossmaxfrags = 256;
+		else if (dmabuf->ossmaxfrags < 2)
+			dmabuf->ossmaxfrags = 2;
+		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
+		while (val < 8192) {
+			val <<= 1;
+			dmabuf->ossmaxfrags <<= 1;
+		}
+		while (val > 65536) {
+			val >>= 1;
+			dmabuf->ossmaxfrags >>= 1;
+		}
+		dmabuf->ready = 0;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
+		       dmabuf->ossfragsize, dmabuf->ossmaxfrags);
+#endif
+		return 0;
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+					return val;
+			} else {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+					return val;
+			}
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		abinfo.fragsize = dmabuf->userfragsize;
+		abinfo.fragstotal = dmabuf->userfrags;
+		if (dmabuf->mapped)
+			abinfo.bytes = dmabuf->dmasize;
+		else
+			abinfo.bytes = ali_get_free_write_space(state);
+		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n",
+		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+		       abinfo.fragstotal);
+#endif
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (codec_independent_spdif_locked > 0) {
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
+				return val;
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
+					return val;
+			} else {
+				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+					return val;
+			}
+		}
+		spin_lock_irqsave(&state->card->lock, flags);
+		val = ali_get_free_write_space(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.ptr = dmabuf->hwptr;
+		cinfo.blocks = val / dmabuf->userfragsize;
+		if (codec_independent_spdif_locked > 0) {
+			if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+				dmabuf->count += val;
+				dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+				__ali_update_lvi(state, 2);
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
+					dmabuf->count += val;
+					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+					__ali_update_lvi(state, 3);
+				}
+			} else {
+				if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+					dmabuf->count += val;
+					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+					__ali_update_lvi(state, 0);
+				}
+			}
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
+		       cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		abinfo.bytes = ali_get_available_read_data(state);
+		abinfo.fragsize = dmabuf->userfragsize;
+		abinfo.fragstotal = dmabuf->userfrags;
+		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n",
+		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
+		       abinfo.fragstotal);
+#endif
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		val = ali_get_available_read_data(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = val / dmabuf->userfragsize;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			dmabuf->count -= val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
+			__ali_update_lvi(state, 1);
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
+		       cinfo.blocks, cinfo.ptr, dmabuf->count);
+#endif
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+	case SNDCTL_DSP_NONBLOCK:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_NONBLOCK\n");
+#endif
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+	case SNDCTL_DSP_GETCAPS:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETCAPS\n");
+#endif
+		return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+				DSP_CAP_MMAP | DSP_CAP_BIND, (int *) arg);
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
+#endif
+		return put_user(dmabuf->trigger, (int *) arg);
+	case SNDCTL_DSP_SETTRIGGER:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+#if defined(DEBUG) || defined(DEBUG_MMAP)
+		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
+#endif
+		if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+			stop_adc(state);
+		}
+		if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+			stop_dac(state);
+		}
+		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
+			stop_spdifout(state);
+		}
+		dmabuf->trigger = val;
+		if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+			if (!dmabuf->write_channel) {
+				dmabuf->ready = 0;
+				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
+				if (!dmabuf->write_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 0);
+				spin_unlock_irqrestore(&state->card->lock,
+						       flags);
+			} else
+				start_dac(state);
+		}
+		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
+			if (!dmabuf->codec_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
+				if (!dmabuf->codec_spdifout_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 2);
+				spin_unlock_irqrestore(&state->card->lock,
+						       flags);
+			} else
+				start_spdifout(state);
+		}
+		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
+			if (!dmabuf->controller_spdifout_channel) {
+				dmabuf->ready = 0;
+				dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
+				if (!dmabuf->controller_spdifout_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				ali_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = ali_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__ali_update_lvi(state, 3);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			} else
+				start_spdifout(state);
+		}
+		if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+			if (!dmabuf->read_channel) {
+				dmabuf->ready = 0;
+				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+				if (!dmabuf->read_channel)
+					return -EBUSY;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+				return ret;
+			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock,
+						  flags);
+				ali_update_ptr(state);
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = 0;
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+			ali_update_lvi(state, 1);
+			start_adc(state);
+		}
+		return 0;
+	case SNDCTL_DSP_SETDUPLEX:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETDUPLEX\n");
+#endif
+		return -EINVAL;
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		ali_update_ptr(state);
+		val = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
+#endif
+		return put_user(val, (int *) arg);
+	case SOUND_PCM_READ_RATE:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
+#endif
+		return put_user(dmabuf->rate, (int *) arg);
+	case SOUND_PCM_READ_CHANNELS:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_CHANNELS\n");
+#endif
+		return put_user(2, (int *) arg);
+	case SOUND_PCM_READ_BITS:
+#ifdef DEBUG
+		printk("SOUND_PCM_READ_BITS\n");
+#endif
+		return put_user(AFMT_S16_LE, (int *) arg);
+	case SNDCTL_DSP_SETSPDIF:	/* Set S/PDIF Control register */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_SETSPDIF\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Check to make sure the codec supports S/PDIF transmitter */
+		if ((state->card->ac97_features & 4)) {
+			/* mask out the transmitter speed bits so the user can't set them */
+			val &= ~0x3000;
+			/* Add the current transmitter speed bits to the passed value */
+			ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+			val |= (ret & 0x3000);
+			ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
+			if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
+				printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
+				return -EFAULT;
+			}
+		}
+#ifdef DEBUG
+		else
+			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+#endif
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_GETSPDIF:	/* Get S/PDIF Control register */
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETSPDIF\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Check to make sure the codec supports S/PDIF transmitter */
+		if (!(state->card->ac97_features & 4)) {
+#ifdef DEBUG
+			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
+#endif
+			val = 0;
+		} else {
+			val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
+		}
+
+		return put_user(val, (int *) arg);
+//end add support spdif out
+//add support 4,6 channel
+	case SNDCTL_DSP_GETCHANNELMASK:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_GETCHANNELMASK\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		/* Based on AC'97 DAC support, not ICH hardware */
+		val = DSP_BIND_FRONT;
+		if (state->card->ac97_features & 0x0004)
+			val |= DSP_BIND_SPDIF;
+		if (state->card->ac97_features & 0x0080)
+			val |= DSP_BIND_SURR;
+		if (state->card->ac97_features & 0x0140)
+			val |= DSP_BIND_CENTER_LFE;
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_BIND_CHANNEL:
+#ifdef DEBUG
+		printk("SNDCTL_DSP_BIND_CHANNEL\n");
+#endif
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val == DSP_BIND_QUERY) {
+			val = DSP_BIND_FRONT;	/* Always report this as being enabled */
+			if (state->card->ac97_status & SPDIF_ON)
+				val |= DSP_BIND_SPDIF;
+			else {
+				if (state->card->ac97_status & SURR_ON)
+					val |= DSP_BIND_SURR;
+				if (state->card->
+				    ac97_status & CENTER_LFE_ON)
+					val |= DSP_BIND_CENTER_LFE;
+			}
+		} else {	/* Not a query, set it */
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+			if (dmabuf->enable == DAC_RUNNING) {
+				stop_dac(state);
+			}
+			if (val & DSP_BIND_SPDIF) {	/* Turn on SPDIF */
+				/*  Ok, this should probably define what slots
+				 *  to use. For now, we'll only set it to the
+				 *  defaults:
+				 * 
+				 *   non multichannel codec maps to slots 3&4
+				 *   2 channel codec maps to slots 7&8
+				 *   4 channel codec maps to slots 6&9
+				 *   6 channel codec maps to slots 10&11
+				 *
+				 *  there should be some way for the app to
+				 *  select the slot assignment.
+				 */
+				i_scr = inl(state->card->iobase + ALI_SCR);
+				if (codec_independent_spdif_locked > 0) {
+
+					if ((i_scr & 0x00300000) == 0x00100000) {
+						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+					} else {
+						if ((i_scr & 0x00300000) == 0x00200000) {
+							ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+						} else {
+							if ((i_scr & 0x00300000) == 0x00300000) {
+								ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+							}
+						}
+					}
+				} else {	/* codec spdif out (pcm out share ) */
+					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate);	//I do not modify
+				}
+
+				if (!(state->card->ac97_status & SPDIF_ON))
+					val &= ~DSP_BIND_SPDIF;
+			} else {
+				int mask;
+				int channels;
+				/* Turn off S/PDIF if it was on */
+				if (state->card->ac97_status & SPDIF_ON)
+					ali_set_spdif_output(state, -1, 0);
+				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:
+					val = DSP_BIND_FRONT;
+					channels = 2;
+					break;
+				}
+				ali_set_dac_channels(state, channels);
+				/* check that they really got turned on */
+				if (!state->card->ac97_status & SURR_ON)
+					val &= ~DSP_BIND_SURR;
+				if (!state->card->
+				    ac97_status & CENTER_LFE_ON)
+					val &= ~DSP_BIND_CENTER_LFE;
+			}
+		}
+		return put_user(val, (int *) arg);
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int ali_open(struct inode *inode, struct file *file)
+{
+	int i = 0;
+	struct ali_card *card = devs;
+	struct ali_state *state = NULL;
+	struct dmabuf *dmabuf = NULL;
+	unsigned int i_scr;
+	
+	/* find an available virtual channel (instance of /dev/dsp) */
+	
+	while (card != NULL) {
+
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ / 20);
+		}
+
+		for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
+			if (card->states[i] == NULL) {
+				state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+				if (state == NULL)
+					return -ENOMEM;
+				memset(state, 0, sizeof(struct ali_state));
+				dmabuf = &state->dmabuf;
+				goto found_virt;
+			}
+		}
+		card = card->next;
+	}
+
+	/* no more virtual channel avaiable */
+	if (!state)
+		return -ENODEV;
+found_virt:
+	/* initialize the virtual channel */
+
+	state->virt = i;
+	state->card = card;
+	state->magic = ALI5455_STATE_MAGIC;
+	init_waitqueue_head(&dmabuf->wait);
+	init_MUTEX(&state->open_sem);
+	file->private_data = state;
+	dmabuf->trigger = 0;
+	/* allocate hardware channels */
+	if (file->f_mode & FMODE_READ) {
+		if ((dmabuf->read_channel =
+		     card->alloc_rec_pcm_channel(card)) == NULL) {
+			kfree(card->states[i]);
+			card->states[i] = NULL;
+			return -EBUSY;
+		}
+		dmabuf->trigger |= PCM_ENABLE_INPUT;
+		ali_set_adc_rate(state, 8000);
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (codec_independent_spdif_locked > 0) {
+			if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
+				kfree(card->states[i]);
+				card->states[i] = NULL;
+				return -EBUSY;
+			}
+			dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+			ali_set_codecspdifout_rate(state, codec_independent_spdif_locked);	//It must add
+			i_scr = inl(state->card->iobase + ALI_SCR);
+			if ((i_scr & 0x00300000) == 0x00100000) {
+				ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+			} else {
+				if ((i_scr & 0x00300000) == 0x00200000) {
+					ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
+				} else {
+					if ((i_scr & 0x00300000) == 0x00300000) {
+						ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
+					} else {
+						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
+					}
+				}
+
+			}
+		} else {
+			if (controller_independent_spdif_locked > 0) {
+				if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
+					kfree(card->states[i]);
+					card->states[i] = NULL;
+					return -EBUSY;
+				}
+				dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
+				ali_set_spdifout_rate(state, controller_independent_spdif_locked);
+			} else {
+				if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
+					kfree(card->states[i]);
+					card->states[i] = NULL;
+					return -EBUSY;
+				}
+				/* Initialize to 8kHz?  What if we don't support 8kHz? */
+				/*  Let's change this to check for S/PDIF stuff */
+
+				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
+				if (codec_pcmout_share_spdif_locked) {
+					ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
+					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
+				} else {
+					ali_set_dac_rate(state, 8000);
+				}
+			}
+
+		}
+	}
+
+	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+	   /dev/dspW will accept 16-bits sample, but we don't support those so we
+	   set it immediately to stereo and 16bit, which is all we do support */
+	dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
+	dmabuf->ossfragsize = 0;
+	dmabuf->ossmaxfrags = 0;
+	dmabuf->subdivision = 0;
+	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+	return 0;
+}
+
+static int ali_release(struct inode *inode, struct file *file)
+{
+	struct ali_state *state = (struct ali_state *) file->private_data;
+	struct ali_card *card = state->card;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	lock_kernel();
+	
+	/* stop DMA state machine and free DMA buffers/channels */
+	if (dmabuf->trigger & PCM_ENABLE_OUTPUT)
+		drain_dac(state, 0);
+
+	if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)
+		drain_spdifout(state, 0);
+	
+	if (dmabuf->trigger & PCM_ENABLE_INPUT)
+		stop_adc(state);
+	
+	spin_lock_irqsave(&card->lock, flags);
+	dealloc_dmabuf(state);
+	if (file->f_mode & FMODE_WRITE) {
+		if (codec_independent_spdif_locked > 0) {
+			state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
+		} else {
+			if (controller_independent_spdif_locked > 0)
+				state->card->free_pcm_channel(state->card,
+							      dmabuf->controller_spdifout_channel->num);
+			else state->card->free_pcm_channel(state->card,
+							      dmabuf->write_channel->num);
+		}
+	}
+	if (file->f_mode & FMODE_READ)
+		state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
+
+	state->card->states[state->virt] = NULL;
+	kfree(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+	unlock_kernel();
+	return 0;
+}
+
+static /*const */ struct file_operations ali_audio_fops = {
+	owner:THIS_MODULE, 
+	llseek:no_llseek, 
+	read:ali_read,
+	write:ali_write, 
+	poll:ali_poll,
+	ioctl:ali_ioctl,
+	mmap:ali_mmap,
+	open:ali_open,
+	release:ali_release,
+};
+
+/* Read AC97 codec registers */
+static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct ali_card *card = dev->private_data;
+	int count1 = 100;
+	char val;
+	unsigned short int data, count, addr1, addr2;
+
+	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+		udelay(1);
+
+	addr1 = reg;
+	reg |= 0x0080;
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x08)
+			break;
+	}
+	if (count == 0x7f)
+		return -1;
+	outw(reg, (card->iobase + ALI_CPR) + 2);
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x02) {
+			data = inw(card->iobase + ALI_SPR);
+			addr2 = inw((card->iobase + ALI_SPR) + 2);
+			break;
+		}
+	}
+	if (count == 0x7f)
+		return -1;
+	if (addr2 != addr1)
+		return -1;
+	return ((u16) data);
+}
+
+/* write ac97 codec register   */
+
+static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct ali_card *card = dev->private_data;
+	int count1 = 100;
+	unsigned long flags;
+	char val;
+	unsigned short int count;
+
+	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
+		udelay(1);
+
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x08)
+			break;
+	}
+	if (count == 0x7f) {
+		printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n");
+		return;
+	}
+	outw(data, (card->iobase + ALI_CPR));
+	outb(reg, (card->iobase + ALI_CPR) + 2);
+	for (count = 0; count < 0x7f; count++) {
+		val = inb(card->iobase + ALI_CSPSR);
+		if (val & 0x01)
+			break;
+	}
+	if (count == 0x7f) {
+		printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n");
+		return;
+	}
+	return;
+}
+
+/* OSS /dev/mixer file operation methods */
+
+static int ali_open_mixdev(struct inode *inode, struct file *file)
+{
+	int i;
+	int minor = MINOR(inode->i_rdev);
+	struct ali_card *card = devs;
+	for (card = devs; card != NULL; card = card->next) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ / 20);
+		}
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+			if (card->ac97_codec[i] != NULL
+			    && card->ac97_codec[i]->dev_mixer == minor) {
+				file->private_data = card->ac97_codec[i];
+				return 0;
+			}
+	}
+	return -ENODEV;
+}
+
+static int ali_ioctl_mixdev(struct inode *inode,
+			    struct file *file,
+			    unsigned int cmd, unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const */ struct file_operations ali_mixer_fops = {
+	owner:THIS_MODULE, 
+	llseek:no_llseek, 
+	ioctl:ali_ioctl_mixdev,
+	open:ali_open_mixdev,
+};
+
+/* AC97 codec initialisation.  These small functions exist so we don't
+   duplicate code between module init and apm resume */
+
+static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
+{
+	unsigned int i = 1;
+	u32 reg = inl(card->iobase + ALI_RTSR);
+	if (ac97_number) {
+		while (i < 100) {
+
+			reg = inl(card->iobase + ALI_RTSR);
+			if (reg & 0x40) {
+				break;
+			} else {
+				outl(reg | 0x00000040,
+				     card->iobase + 0x34);
+				udelay(1);
+			}
+			i++;
+		}
+
+	} else {
+		while (i < 100) {
+			reg = inl(card->iobase + ALI_RTSR);
+			if (reg & 0x80) {
+				break;
+			} else {
+				outl(reg | 0x00000080,
+				     card->iobase + 0x34);
+				udelay(1);
+			}
+			i++;
+		}
+	}
+
+	if (ac97_number)
+		return reg & 0x40;
+	else
+		return reg & 0x80;
+}
+
+static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
+{
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
+	ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
+	return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
+}
+
+
+static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
+{
+	/* Returns 0 on failure */
+	int i;
+	u16 addr;
+	if (ac97_probe_codec(codec) == 0)
+		return 0;
+	/* ac97_probe_codec is success ,then begin to init codec */
+	ali_ac97_set(codec, AC97_RESET, 0xffff);
+	if (card->channel[0].used == 1) {
+		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+		ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
+		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+	}
+
+	if (card->channel[2].used == 1)	//if MICin then init codec
+	{
+		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
+		ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
+		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
+		ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
+	}
+
+	ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
+	ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
+	ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
+	ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
+	ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
+	ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
+	ali_ac97_set(codec, 0x38, 0x0000);
+	addr = ali_ac97_get(codec, 0x2a);
+	ali_ac97_set(codec, 0x2a, addr | 0x0001);
+	addr = ali_ac97_get(codec, 0x2a);
+	addr = ali_ac97_get(codec, 0x28);
+	ali_ac97_set(codec, 0x2c, 0xbb80);
+	addr = ali_ac97_get(codec, 0x2c);
+	/* power it all up */
+	ali_ac97_set(codec, AC97_POWER_CONTROL,
+		     ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+	/* wait for analog ready */
+	for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 20);
+	}
+	/* FIXME !! */
+	i++;
+	return i;
+}
+
+
+/* I clone ali5455(2.4.7 )  not clone i810_audio(2.4.18)  */
+
+static int ali_reset_5455(struct ali_card *card)
+{
+	outl(0x80000003, card->iobase + ALI_SCR);
+	outl(0x83838383, card->iobase + ALI_FIFOCR1);
+	outl(0x83838383, card->iobase + ALI_FIFOCR2);
+	if (controller_pcmout_share_spdif_locked > 0) {
+		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+		     card->iobase + ALI_SPDIFICS);
+		outl(0x0408000a, card->iobase + ALI_INTERFACECR);
+	} else {
+		if (codec_independent_spdif_locked > 0) {
+			outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR);	// now I select slot 7 & 8
+			outl(0x00200000, card->iobase + ALI_INTERFACECR);	//enable codec independent spdifout 
+		} else
+			outl(0x04080002, card->iobase + ALI_INTERFACECR);
+	}
+
+	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
+	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
+	if (controller_independent_spdif_locked > 0)
+		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
+		     card->iobase + ALI_SPDIFICS);
+	return 1;
+}
+
+
+static int ali_ac97_random_init_stuff(struct ali_card
+				      *card)
+{
+	u32 reg = inl(card->iobase + ALI_SCR);
+	int i = 0;
+	reg = inl(card->iobase + ALI_SCR);
+	if ((reg & 2) == 0)	/* Cold required */
+		reg |= 2;
+	else
+		reg |= 1;	/* Warm */
+	reg &= ~0x80000000;	/* ACLink on */
+	outl(reg, card->iobase + ALI_SCR);
+
+	while (i < 10) {
+		if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
+			break;
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ / 20);
+		i++;
+	}
+	if (i == 10) {
+		printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
+		return 0;
+	}
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 2);
+	return 1;
+}
+
+/* AC97 codec initialisation. */
+
+static int __init ali_ac97_init(struct ali_card *card)
+{
+	int num_ac97 = 0;
+	int total_channels = 0;
+	struct ac97_codec *codec;
+	u16 eid;
+
+	if (!ali_ac97_random_init_stuff(card))
+		return 0;
+
+	/* Number of channels supported */
+	/* What about the codec?  Just because the ICH supports */
+	/* multiple channels doesn't mean the codec does.       */
+	/* we'll have to modify this in the codec section below */
+	/* to reflect what the codec has.                       */
+	/* ICH and ICH0 only support 2 channels so don't bother */
+	/* to check....                                         */
+	inl(card->iobase + ALI_CPR);
+	card->channels = 2;
+
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+
+		/* Assume codec isn't available until we go through the
+		 * gauntlet below */
+		card->ac97_codec[num_ac97] = NULL;
+		/* The ICH programmer's reference says you should   */
+		/* check the ready status before probing. So we chk */
+		/*   What do we do if it's not ready?  Wait and try */
+		/*   again, or abort?                               */
+		if (!ali_ac97_exists(card, num_ac97)) {
+			if (num_ac97 == 0)
+				printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
+			break;
+		}
+
+		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		memset(codec, 0, sizeof(struct ac97_codec));
+		/* initialize some basic codec information, other fields will be filled
+		   in ac97_probe_codec */
+		codec->private_data = card;
+		codec->id = num_ac97;
+		codec->codec_read = ali_ac97_get;
+		codec->codec_write = ali_ac97_set;
+		if (!ali_ac97_probe_and_powerup(card, codec)) {
+			printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
+			     num_ac97);
+			kfree(codec);
+			break;	/* it didn't work */
+		}
+		
+		/* Store state information about S/PDIF transmitter */
+		card->ac97_status = 0;
+		/* Don't attempt to get eid until powerup is complete */
+		eid = ali_ac97_get(codec, AC97_EXTENDED_ID);
+		if (eid == 0xFFFFFF) {
+			printk(KERN_ERR "ali_audio: no codec attached ?\n");
+			kfree(codec);
+			break;
+		}
+
+		card->ac97_features = eid;
+		/* Now check the codec for useful features to make up for
+		   the dumbness of the ali5455 hardware engine */
+		if (!(eid & 0x0001))
+			printk(KERN_WARNING
+			       "ali_audio: only 48Khz playback available.\n");
+		else {
+			if (!ali_ac97_enable_variable_rate(codec)) {
+				printk(KERN_WARNING
+				       "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
+				card->ac97_features &= ~1;
+			}
+		}
+
+		/* Determine how many channels the codec(s) support   */
+		/*   - The primary codec always supports 2            */
+		/*   - If the codec supports AMAP, surround DACs will */
+		/*     automaticlly get assigned to slots.            */
+		/*     * Check for surround DACs and increment if     */
+		/*       found.                                       */
+		/*   - Else check if the codec is revision 2.2        */
+		/*     * If surround DACs exist, assign them to slots */
+		/*       and increment channel count.                 */
+
+		/* All of this only applies to ICH2 and above. ICH    */
+		/* and ICH0 only support 2 channels.  ICH2 will only  */
+		/* support multiple codecs in a "split audio" config. */
+		/* as described above.                                */
+
+		/* TODO: Remove all the debugging messages!           */
+
+		if ((eid & 0xc000) == 0)	/* primary codec */
+			total_channels += 2;
+		if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
+			printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
+			kfree(codec);
+			break;
+		}
+		card->ac97_codec[num_ac97] = codec;
+	}
+	/* pick the minimum of channels supported by ICHx or codec(s) */
+	card->channels = (card->channels > total_channels) ? total_channels : card->channels;
+	return num_ac97;
+}
+
+static void __init ali_configure_clocking(void)
+{
+	struct ali_card *card;
+	struct ali_state *state;
+	struct dmabuf *dmabuf;
+	unsigned int i, offset, new_offset;
+	unsigned long flags;
+	card = devs;
+
+	/* We could try to set the clocking for multiple cards, but can you even have
+	 * more than one ali in a machine?  Besides, clocking is global, so unless
+	 * someone actually thinks more than one ali in a machine is possible and
+	 * decides to rewrite that little bit, setting the rate for more than one card
+	 * is a waste of time.
+	 */
+	if (card != NULL) {
+		state = card->states[0] = (struct ali_state *)
+		    kmalloc(sizeof(struct ali_state), GFP_KERNEL);
+		if (state == NULL)
+			return;
+		memset(state, 0, sizeof(struct ali_state));
+		dmabuf = &state->dmabuf;
+		dmabuf->write_channel = card->alloc_pcm_channel(card);
+		state->virt = 0;
+		state->card = card;
+		state->magic = ALI5455_STATE_MAGIC;
+		init_waitqueue_head(&dmabuf->wait);
+		init_MUTEX(&state->open_sem);
+		dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
+		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		ali_set_dac_rate(state, 48000);
+		if (prog_dmabuf(state, 0) != 0)
+			goto config_out_nodmabuf;
+		
+		if (dmabuf->dmasize < 16384)
+			goto config_out;
+		
+		dmabuf->count = dmabuf->dmasize;
+		outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
+		
+		save_flags(flags);
+		cli();
+		start_dac(state);
+		offset = ali_get_dma_addr(state, 0);
+		mdelay(50);
+		new_offset = ali_get_dma_addr(state, 0);
+		stop_dac(state);
+		
+		outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
+		restore_flags(flags);
+
+		i = new_offset - offset;
+
+		if (i == 0)
+			goto config_out;
+		i = i / 4 * 20;
+		if (i > 48500 || i < 47500) {
+			clocking = clocking * clocking / i;
+		}
+config_out:
+		dealloc_dmabuf(state);
+config_out_nodmabuf:
+		state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num);
+		kfree(state);
+		card->states[0] = NULL;
+	}
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
+   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+
+static int __init ali_probe(struct pci_dev *pci_dev, const struct pci_device_id
+			    *pci_id)
+{
+	struct ali_card *card;
+	if (pci_enable_device(pci_dev))
+		return -EIO;
+	if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
+		printk(KERN_ERR "ali5455: architecture does not support"
+		       " 32bit PCI busmaster DMA\n");
+		return -ENODEV;
+	}
+
+	if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ali_audio: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(*card));
+	card->initializing = 1;
+	card->iobase = pci_resource_start(pci_dev, 0);
+	card->pci_dev = pci_dev;
+	card->pci_id = pci_id->device;
+	card->irq = pci_dev->irq;
+	card->next = devs;
+	card->magic = ALI5455_CARD_MAGIC;
+#ifdef CONFIG_PM
+	card->pm_suspended = 0;
+#endif
+	spin_lock_init(&card->lock);
+	devs = card;
+	pci_set_master(pci_dev);
+	printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], card->iobase, card->irq);
+	card->alloc_pcm_channel = ali_alloc_pcm_channel;
+	card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
+	card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
+	card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
+	card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
+	card->free_pcm_channel = ali_free_pcm_channel;
+	card->channel[0].offset = 0;
+	card->channel[0].port = 0x40;
+	card->channel[0].num = 0;
+	card->channel[1].offset = 0;
+	card->channel[1].port = 0x50;
+	card->channel[1].num = 1;
+	card->channel[2].offset = 0;
+	card->channel[2].port = 0x60;
+	card->channel[2].num = 2;
+	card->channel[3].offset = 0;
+	card->channel[3].port = 0x70;
+	card->channel[3].num = 3;
+	card->channel[4].offset = 0;
+	card->channel[4].port = 0xb0;
+	card->channel[4].num = 4;
+	/* claim our iospace and irq */
+	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
+	if (request_irq(card->irq, &ali_interrupt, SA_SHIRQ,
+			card_names[pci_id->driver_data], card)) {
+		printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
+		       card->irq);
+		release_region(card->iobase, 256);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	if (ali_reset_5455(card) <= 0) {
+		unregister_sound_dsp(card->dev_audio);
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+
+	/* initialize AC97 codec and register /dev/mixer */
+	if (ali_ac97_init(card) < 0) {
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+	
+	pci_set_drvdata(pci_dev, card);
+	
+	if (clocking == 0) {
+		clocking = 48000;
+		ali_configure_clocking();
+	}
+
+	/* register /dev/dsp */
+	if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
+		int i;
+		printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
+		release_region(card->iobase, 256);
+		free_irq(card->irq, card);
+		for (i = 0; i < NR_AC97; i++)
+			if (card->ac97_codec[i] != NULL) {
+				unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
+				kfree(card->ac97_codec[i]);
+			}
+		kfree(card);
+		return -ENODEV;
+	}
+	card->initializing = 0;
+	return 0;
+}
+
+static void __devexit ali_remove(struct pci_dev *pci_dev)
+{
+	int i;
+	struct ali_card *card = pci_get_drvdata(pci_dev);
+	/* free hardware resources */
+	free_irq(card->irq, devs);
+	release_region(card->iobase, 256);
+	/* unregister audio devices */
+	for (i = 0; i < NR_AC97; i++)
+		if (card->ac97_codec[i] != NULL) {
+			unregister_sound_mixer(card->ac97_codec[i]->
+					       dev_mixer);
+			kfree(card->ac97_codec[i]);
+			card->ac97_codec[i] = NULL;
+		}
+	unregister_sound_dsp(card->dev_audio);
+	kfree(card);
+}
+
+#ifdef CONFIG_PM
+static int ali_pm_suspend(struct pci_dev *dev, u32 pm_state)
+{
+	struct ali_card *card = pci_get_drvdata(dev);
+	struct ali_state *state;
+	unsigned long flags;
+	struct dmabuf *dmabuf;
+	int i, num_ac97;
+
+	if (!card)
+		return 0;
+	spin_lock_irqsave(&card->lock, flags);
+	card->pm_suspended = 1;
+	for (i = 0; i < NR_HW_CH; i++) {
+		state = card->states[i];
+		if (!state)
+			continue;
+		/* this happens only if there are open files */
+		dmabuf = &state->dmabuf;
+		if (dmabuf->enable & DAC_RUNNING ||
+		    (dmabuf->count
+		     && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
+			state->pm_saved_dac_rate = dmabuf->rate;
+			stop_dac(state);
+		} else {
+			state->pm_saved_dac_rate = 0;
+		}
+		if (dmabuf->enable & ADC_RUNNING) {
+			state->pm_saved_adc_rate = dmabuf->rate;
+			stop_adc(state);
+		} else {
+			state->pm_saved_adc_rate = 0;
+		}
+		dmabuf->ready = 0;
+		dmabuf->swptr = dmabuf->hwptr = 0;
+		dmabuf->count = dmabuf->total_bytes = 0;
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+	/* save mixer settings */
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		struct ac97_codec *codec = card->ac97_codec[num_ac97];
+		if (!codec)
+			continue;
+		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+			if ((supported_mixer(codec, i)) && (codec->read_mixer)) {
+				card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i);
+			}
+		}
+	}
+	pci_save_state(dev, card->pm_save_state);	/* XXX do we need this? */
+	pci_disable_device(dev);	/* disable busmastering */
+	pci_set_power_state(dev, 3);	/* Zzz. */
+	return 0;
+}
+
+
+static int ali_pm_resume(struct pci_dev *dev)
+{
+	int num_ac97, i = 0;
+	struct ali_card *card = pci_get_drvdata(dev);
+	pci_enable_device(dev);
+	pci_restore_state(dev, card->pm_save_state);
+	/* observation of a toshiba portege 3440ct suggests that the 
+	   hardware has to be more or less completely reinitialized from
+	   scratch after an apm suspend.  Works For Me.   -dan */
+	ali_ac97_random_init_stuff(card);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		struct ac97_codec *codec = card->ac97_codec[num_ac97];
+		/* check they haven't stolen the hardware while we were
+		   away */
+		if (!codec || !ali_ac97_exists(card, num_ac97)) {
+			if (num_ac97)
+				continue;
+			else
+				BUG();
+		}
+		if (!ali_ac97_probe_and_powerup(card, codec))
+			BUG();
+		if ((card->ac97_features & 0x0001)) {
+			/* at probe time we found we could do variable
+			   rates, but APM suspend has made it forget
+			   its magical powers */
+			if (!ali_ac97_enable_variable_rate(codec))
+				BUG();
+		}
+		/* we lost our mixer settings, so restore them */
+		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+			if (supported_mixer(codec, i)) {
+				int val = card->pm_saved_mixer_settings[i][num_ac97];
+				codec->mixer_state[i] = val;
+				codec->write_mixer(codec, i,
+						   (val & 0xff),
+						   ((val >> 8) & 0xff));
+			}
+		}
+	}
+
+	/* we need to restore the sample rate from whatever it was */
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		if (state) {
+			if (state->pm_saved_adc_rate)
+				ali_set_adc_rate(state, state->pm_saved_adc_rate);
+			if (state->pm_saved_dac_rate)
+				ali_set_dac_rate(state, state->pm_saved_dac_rate);
+		}
+	}
+
+	card->pm_suspended = 0;
+	/* any processes that were reading/writing during the suspend
+	   probably ended up here */
+	for (i = 0; i < NR_HW_CH; i++) {
+		struct ali_state *state = card->states[i];
+		if (state)
+			wake_up(&state->dmabuf.wait);
+	}
+	return 0;
+}
+#endif				/* CONFIG_PM */
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("ALI 5455 audio support");
+MODULE_LICENSE("GPL");
+MODULE_PARM(clocking, "i");
+MODULE_PARM(strict_clocking, "i");
+MODULE_PARM(codec_pcmout_share_spdif_locked, "i");
+MODULE_PARM(codec_independent_spdif_locked, "i");
+MODULE_PARM(controller_pcmout_share_spdif_locked, "i");
+MODULE_PARM(controller_independent_spdif_locked, "i");
+#define ALI5455_MODULE_NAME "ali5455"
+static struct pci_driver ali_pci_driver = {
+	name:ALI5455_MODULE_NAME, id_table:ali_pci_tbl, probe:ali_probe,
+	    remove:__devexit_p(ali_remove),
+#ifdef CONFIG_PM
+	suspend:ali_pm_suspend, resume:ali_pm_resume,
+#endif				/* CONFIG_PM */
+};
+
+static int __init ali_init_module(void)
+{
+	if (!pci_present())	/* No PCI bus in this machine! */
+		return -ENODEV;
+	printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
+	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+
+	if (codec_independent_spdif_locked > 0) {
+		if (codec_independent_spdif_locked == 32000
+		    || codec_independent_spdif_locked == 44100
+		    || codec_independent_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			codec_independent_spdif_locked = 0;
+		}
+	}
+	if (controller_independent_spdif_locked > 0) {
+		if (controller_independent_spdif_locked == 32000
+		    || controller_independent_spdif_locked == 44100
+		    || controller_independent_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			controller_independent_spdif_locked = 0;
+		}
+	}
+
+	if (codec_pcmout_share_spdif_locked > 0) {
+		if (codec_pcmout_share_spdif_locked == 32000
+		    || codec_pcmout_share_spdif_locked == 44100
+		    || codec_pcmout_share_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			codec_pcmout_share_spdif_locked = 0;
+		}
+	}
+	if (controller_pcmout_share_spdif_locked > 0) {
+		if (controller_pcmout_share_spdif_locked == 32000
+		    || controller_pcmout_share_spdif_locked == 44100
+		    || controller_pcmout_share_spdif_locked == 48000) {
+			printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
+		} else {
+			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
+			controller_pcmout_share_spdif_locked = 0;
+		}
+	}
+	if (!pci_register_driver(&ali_pci_driver)) {
+		pci_unregister_driver(&ali_pci_driver);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit ali_cleanup_module(void)
+{
+	pci_unregister_driver(&ali_pci_driver);
+}
+
+module_init(ali_init_module);
+module_exit(ali_cleanup_module);
+/*
+Local Variables:
+c-basic-offset: 8
+End:
+*/
diff -urN linux-2.4.20-pre2/drivers/usb/devio.c linux-2.4.20-pre3/drivers/usb/devio.c
--- linux-2.4.20-pre2/drivers/usb/devio.c	Sat Aug 17 14:18:23 2002
+++ linux-2.4.20-pre3/drivers/usb/devio.c	Sat Aug 17 14:18:56 2002
@@ -138,7 +138,7 @@
 	return ret;
 }
 
-extern inline unsigned int ld2(unsigned int x)
+static inline unsigned int ld2(unsigned int x)
 {
         unsigned int r = 0;
         
@@ -188,7 +188,7 @@
         kfree(as);
 }
 
-extern __inline__ void async_newpending(struct async *as)
+static inline void async_newpending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -198,7 +198,7 @@
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ void async_removepending(struct async *as)
+static inline void async_removepending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -209,7 +209,7 @@
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+static inline struct async *async_getcompleted(struct dev_state *ps)
 {
         unsigned long flags;
         struct async *as = NULL;
@@ -224,7 +224,7 @@
         return as;
 }
 
-extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb)
+static inline struct async *async_getpending(struct dev_state *ps, void *userurb)
 {
         unsigned long flags;
         struct async *as;
diff -urN linux-2.4.20-pre2/drivers/usb/kaweth.c linux-2.4.20-pre3/drivers/usb/kaweth.c
--- linux-2.4.20-pre2/drivers/usb/kaweth.c	Sat Aug 17 14:18:24 2002
+++ linux-2.4.20-pre3/drivers/usb/kaweth.c	Sat Aug 17 14:18:57 2002
@@ -143,6 +143,7 @@
 	{ USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
 	{ USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
 	{ USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
+	{ USB_DEVICE(0x1485, 0x0001) }, /* Silicom USB-Ethernet Adapter */
 	{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ 
 	{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ 
 	{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ 
diff -urN linux-2.4.20-pre2/drivers/usb/ov511.c linux-2.4.20-pre3/drivers/usb/ov511.c
--- linux-2.4.20-pre2/drivers/usb/ov511.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/drivers/usb/ov511.c	Sat Aug 17 14:18:57 2002
@@ -377,55 +377,18 @@
  *
  * 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
  **********************************************************************/
 
-/* 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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long 
 kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -434,12 +397,9 @@
 rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -447,13 +407,9 @@
 	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)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -462,23 +418,16 @@
 static void 
 rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	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 = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
diff -urN linux-2.4.20-pre2/drivers/usb/ov511.h linux-2.4.20-pre3/drivers/usb/ov511.h
--- linux-2.4.20-pre2/drivers/usb/ov511.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/drivers/usb/ov511.h	Sat Aug 17 14:18:57 2002
@@ -10,7 +10,8 @@
 
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\
+		if (debug >= (level)) info("[%s:%d] " fmt,\
+		__PRETTY_FUNCTION__, \
 		__LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
diff -urN linux-2.4.20-pre2/drivers/usb/pwc-if.c linux-2.4.20-pre3/drivers/usb/pwc-if.c
--- linux-2.4.20-pre2/drivers/usb/pwc-if.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/drivers/usb/pwc-if.c	Sat Aug 17 14:18:57 2002
@@ -179,60 +179,25 @@
 /***************************************************************************/
 /* Private functions */
 
-/* Memory management functions, nicked from cpia.c, which nicked them from
-   bttv.c. So far, I've counted duplication of this code 6 times 
-   (bttv, cpia, ibmcam, ov511, pwc, ieee1394).
- */
-
-/* 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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva, ret;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
         return ret;
 }
 
-static void * rvmalloc(signed long size)
+static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
-        /* Round it off to PAGE_SIZE */
-        size += (PAGE_SIZE - 1);
-        size &= ~(PAGE_SIZE - 1);	
-        
+	size=PAGE_ALIGN(size);
         mem=vmalloc_32(size);
 	if (mem) 
 	{
@@ -240,8 +205,7 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -249,20 +213,16 @@
 	return mem;
 }
 
-static void rvfree(void * mem, signed long size)
+static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr, page;
-        
-        /* Round it off to PAGE_SIZE */
-        size += (PAGE_SIZE - 1);
-        size &= ~(PAGE_SIZE - 1);	
+        unsigned long adr;
+
 	if (mem) 
 	{
 	        adr=(unsigned long) mem;
-		while (size > 0) 
+		while ((long) size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
diff -urN linux-2.4.20-pre2/drivers/usb/se401.c linux-2.4.20-pre3/drivers/usb/se401.c
--- linux-2.4.20-pre2/drivers/usb/se401.c	Sat Aug 17 14:18:24 2002
+++ linux-2.4.20-pre3/drivers/usb/se401.c	Sat Aug 17 14:18:57 2002
@@ -80,54 +80,17 @@
  *
  * 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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -135,12 +98,9 @@
 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);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -148,13 +108,9 @@
 	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)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -162,23 +118,16 @@
 
 static void rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	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 = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -704,7 +653,7 @@
 		return 0;
 
 	/* Check for a valid mode */
-	if (!width || !height)
+	if (width <= 0 || height <= 0)
 		return 1;
 	if ((width & 1) || (height & 1))
 		return 1;
@@ -738,7 +687,8 @@
 static inline void enhance_picture(unsigned char *frame, int len)
 {
 	while (len--) {
-		*frame++=(((*frame^255)*(*frame^255))/255)^255;
+		*frame=(((*frame^255)*(*frame^255))/255)^255;
+		frame++;
 	}
 }
 
@@ -972,7 +922,8 @@
 		/* Fix the top line */
 		framedata+=linelength;
 		for (i=0; i<linelength; i++) {
-			*--framedata=*(framedata+linelength);
+			framedata--;
+			*framedata=*(framedata+linelength);
 		}
 		/* Fix the left side (green is already present) */
 		for (i=0; i<se401->cheight; i++) {
@@ -1425,7 +1376,13 @@
 
 	se401->sizes=cp[4]+cp[5]*256;
 	se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	if (!se401->width)
+		return 1;
 	se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	if (!se401->height) {
+		kfree(se401->width);
+		return 1;
+	}
 	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;
diff -urN linux-2.4.20-pre2/drivers/usb/stv680.c linux-2.4.20-pre3/drivers/usb/stv680.c
--- linux-2.4.20-pre2/drivers/usb/stv680.c	Sat Aug 17 14:18:25 2002
+++ linux-2.4.20-pre3/drivers/usb/stv680.c	Sat Aug 17 14:18:57 2002
@@ -86,7 +86,7 @@
 #define PDEBUG(level, fmt, args...) \
 	do { \
 	if (debug >= level)	\
-		info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args);	\
+		info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args);	\
 	} while (0)
 
 
@@ -111,67 +111,27 @@
  *
  * 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
- *
- * And the STV0680 driver - Kevin
  ********************************************************************/
 
-/* 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.
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa (unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR (adr);
-	kva = uvirt_to_kva (pgd_offset_k (va), va);
-	ret = __pa (kva);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	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);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32 (size);
 	if (!mem)
 		return NULL;
@@ -179,36 +139,25 @@
 	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)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	return mem;
 }
 
 static void rvfree (void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	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)));
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree (mem);
 }
diff -urN linux-2.4.20-pre2/drivers/usb/usb-ohci.c linux-2.4.20-pre3/drivers/usb/usb-ohci.c
--- linux-2.4.20-pre2/drivers/usb/usb-ohci.c	Sat Aug 17 14:18:25 2002
+++ linux-2.4.20-pre3/drivers/usb/usb-ohci.c	Sat Aug 17 14:18:58 2002
@@ -2144,6 +2144,8 @@
 	int timeout = 30;
 	int smm_timeout = 50; /* 0,5 sec */
 	 	
+#ifndef __hppa__
+	/* PA-RISC doesn't have SMM, but PDC might leave IR set */
 	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
 		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
 		dbg("USB HC TakeOver from SMM");
@@ -2154,7 +2156,8 @@
 				return -1;
 			}
 		}
-	}	
+	}
+#endif	
 		
 	/* Disable HC interrupts */
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
@@ -2218,9 +2221,19 @@
 	writel (mask, &ohci->regs->intrstatus);
 
 #ifdef	OHCI_USE_NPS
-	/* required for AMD-756 and some Mac platforms */
-	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
-		&ohci->regs->roothub.a);
+	if(ohci->flags & OHCI_QUIRK_SUCKYIO)
+	{
+		/* NSC 87560 at least requires different setup .. */
+		writel ((roothub_a (ohci) | RH_A_NOCP) &
+			~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS),
+			&ohci->regs->roothub.a);
+	}
+	else
+	{
+		/* required for AMD-756 and some Mac platforms */
+		writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+			&ohci->regs->roothub.a);
+	}
 	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
 #endif	/* OHCI_USE_NPS */
 
@@ -2470,6 +2483,21 @@
 		return ret;
 	}
 	ohci->flags = id->driver_data;
+	
+	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
+	   the USB (fn2). This quirk might apply to more or even all NSC stuff
+	   I don't know.. */
+	   
+	if(dev->vendor == PCI_VENDOR_ID_NS)
+	{
+		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
+		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
+			ohci->flags |= OHCI_QUIRK_SUCKYIO;
+		
+	}
+	
+	if (ohci->flags & OHCI_QUIRK_SUCKYIO)
+		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
 	if (ohci->flags & OHCI_QUIRK_AMD756)
 		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
 
diff -urN linux-2.4.20-pre2/drivers/usb/usb-ohci.h linux-2.4.20-pre3/drivers/usb/usb-ohci.h
--- linux-2.4.20-pre2/drivers/usb/usb-ohci.h	Sat Aug 17 14:18:25 2002
+++ linux-2.4.20-pre3/drivers/usb/usb-ohci.h	Sat Aug 17 14:18:58 2002
@@ -381,6 +381,7 @@
 	atomic_t resume_count;		/* defending against multiple resumes */
 	unsigned long flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
+#define OHCI_QUIRK_SUCKYIO	0x02		/* NSC superio */
 
 	struct ohci_regs * regs;	/* OHCI controller's memory */
 	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
diff -urN linux-2.4.20-pre2/drivers/usb/usbvideo.c linux-2.4.20-pre3/drivers/usb/usbvideo.c
--- linux-2.4.20-pre2/drivers/usb/usbvideo.c	Sat Aug 17 14:18:25 2002
+++ linux-2.4.20-pre3/drivers/usb/usbvideo.c	Sat Aug 17 14:18:58 2002
@@ -58,57 +58,26 @@
 /* Memory management functions */
 /*******************************/
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-unsigned long usbvideo_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));
-			}
-		}
-	}
-	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	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.
+ * This is used when initializing the contents of the area.
  */
 unsigned long usbvideo_kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
-	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
 	return ret;
 }
 
 void *usbvideo_rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -116,13 +85,9 @@
 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	adr = (unsigned long) mem;
 	while (size > 0) {
-		page = usbvideo_kvirt_to_pa(adr);
-		mem_map_reserve(virt_to_page(__va(page)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -130,23 +95,16 @@
 
 void usbvideo_rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (!mem)
 		return;
 
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = usbvideo_kvirt_to_pa(adr);
-		mem_map_unreserve(virt_to_page(__va(page)));
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
diff -urN linux-2.4.20-pre2/drivers/usb/vicam.c linux-2.4.20-pre3/drivers/usb/vicam.c
--- linux-2.4.20-pre2/drivers/usb/vicam.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/drivers/usb/vicam.c	Sat Aug 17 14:18:58 2002
@@ -91,80 +91,25 @@
  *
  ******************************************************************************/
 
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* 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;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
-
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
 
-static void * rvmalloc(signed long size)
+static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
+	size=PAGE_ALIGN(size);
 	mem=vmalloc_32(size);
 	if (mem)
 	{
@@ -172,8 +117,7 @@
 		adr=(unsigned long) mem;
 		while (size > 0)
 		{
-			page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -181,17 +125,16 @@
 	return mem;
 }
 
-static void rvfree(void * mem, signed long size)
+static void rvfree(void * mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	if (mem)
 	{
 		adr=(unsigned long) mem;
-		while (size > 0)
+		while ((long) size > 0)
 		{
-			page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
diff -urN linux-2.4.20-pre2/drivers/video/clgenfb.c linux-2.4.20-pre3/drivers/video/clgenfb.c
--- linux-2.4.20-pre2/drivers/video/clgenfb.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/drivers/video/clgenfb.c	Sat Aug 17 14:18:58 2002
@@ -3089,7 +3089,7 @@
 *********************************************************************/
 
 /* FIXME: use interrupts instead */
-extern inline void clgen_WaitBLT (caddr_t regbase)
+static inline void clgen_WaitBLT (caddr_t regbase)
 {
 	/* now busy-wait until we're done */
 	while (vga_rgfx (regbase, CL_GR31) & 0x08)
diff -urN linux-2.4.20-pre2/fs/Config.in linux-2.4.20-pre3/fs/Config.in
--- linux-2.4.20-pre2/fs/Config.in	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/Config.in	Sat Aug 17 14:18:59 2002
@@ -19,6 +19,9 @@
 
 dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
+dep_tristate 'BeOS file systemv(BeFS) support (read only) (EXPERIMENTAL)' CONFIG_BEFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool '  Debug Befs' CONFIG_BEFS_DEBUG $CONFIG_BEFS_FS
+
 dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS
@@ -99,6 +102,7 @@
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
    dep_mbool '  Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
+   dep_mbool '  Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
       define_tristate CONFIG_SUNRPC y
diff -urN linux-2.4.20-pre2/fs/dcache.c linux-2.4.20-pre3/fs/dcache.c
--- linux-2.4.20-pre2/fs/dcache.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/dcache.c	Sat Aug 17 14:18:59 2002
@@ -1283,6 +1283,7 @@
 
 	dcache_init(mempages);
 	inode_init(mempages);
+	files_init(mempages); 
 	mnt_init(mempages);
 	bdev_cache_init();
 	cdev_cache_init();
diff -urN linux-2.4.20-pre2/fs/dnotify.c linux-2.4.20-pre3/fs/dnotify.c
--- linux-2.4.20-pre2/fs/dnotify.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/dnotify.c	Sat Aug 17 14:18:59 2002
@@ -140,7 +140,7 @@
 
 static int __init dnotify_init(void)
 {
-	dn_cache = kmem_cache_create("dnotify cache",
+	dn_cache = kmem_cache_create("dnotify_cache",
 		sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
 	if (!dn_cache)
 		panic("cannot create dnotify slab cache");
diff -urN linux-2.4.20-pre2/fs/exec.c linux-2.4.20-pre3/fs/exec.c
--- linux-2.4.20-pre2/fs/exec.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/exec.c	Sat Aug 17 14:18:59 2002
@@ -182,25 +182,34 @@
  */
 int copy_strings(int argc,char ** argv, struct linux_binprm *bprm) 
 {
+	struct page *kmapped_page = NULL;
+	char *kaddr = NULL;
+	int ret;
+
 	while (argc-- > 0) {
 		char *str;
 		int len;
 		unsigned long pos;
 
-		if (get_user(str, argv+argc) || !(len = strnlen_user(str, bprm->p)))
-			return -EFAULT;
-		if (bprm->p < len) 
-			return -E2BIG; 
+		if (get_user(str, argv+argc) ||
+				!(len = strnlen_user(str, bprm->p))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		if (bprm->p < len)  {
+			ret = -E2BIG;
+			goto out;
+		}
 
 		bprm->p -= len;
 		/* XXX: add architecture specific overflow check here. */ 
-
 		pos = bprm->p;
+
 		while (len > 0) {
-			char *kaddr;
 			int i, new, err;
-			struct page *page;
 			int offset, bytes_to_copy;
+			struct page *page;
 
 			offset = pos % PAGE_SIZE;
 			i = pos/PAGE_SIZE;
@@ -209,32 +218,44 @@
 			if (!page) {
 				page = alloc_page(GFP_HIGHUSER);
 				bprm->page[i] = page;
-				if (!page)
-					return -ENOMEM;
+				if (!page) {
+					ret = -ENOMEM;
+					goto out;
+				}
 				new = 1;
 			}
-			kaddr = kmap(page);
 
+			if (page != kmapped_page) {
+				if (kmapped_page)
+					kunmap(kmapped_page);
+				kmapped_page = page;
+				kaddr = kmap(kmapped_page);
+			}
 			if (new && offset)
 				memset(kaddr, 0, offset);
 			bytes_to_copy = PAGE_SIZE - offset;
 			if (bytes_to_copy > len) {
 				bytes_to_copy = len;
 				if (new)
-					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
+					memset(kaddr+offset+len, 0,
+						PAGE_SIZE-offset-len);
+			}
+			err = copy_from_user(kaddr+offset, str, bytes_to_copy);
+			if (err) {
+				ret = -EFAULT;
+				goto out;
 			}
-			err = copy_from_user(kaddr + offset, str, bytes_to_copy);
-			kunmap(page);
-
-			if (err)
-				return -EFAULT; 
 
 			pos += bytes_to_copy;
 			str += bytes_to_copy;
 			len -= bytes_to_copy;
 		}
 	}
-	return 0;
+	ret = 0;
+out:
+	if (kmapped_page)
+		kunmap(kmapped_page);
+	return ret;
 }
 
 /*
diff -urN linux-2.4.20-pre2/fs/fcntl.c linux-2.4.20-pre3/fs/fcntl.c
--- linux-2.4.20-pre2/fs/fcntl.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/fcntl.c	Sat Aug 17 14:18:59 2002
@@ -529,7 +529,7 @@
 
 static int __init fasync_init(void)
 {
-	fasync_cache = kmem_cache_create("fasync cache",
+	fasync_cache = kmem_cache_create("fasync_cache",
 		sizeof(struct fasync_struct), 0, 0, NULL, NULL);
 	if (!fasync_cache)
 		panic("cannot create fasync slab cache");
diff -urN linux-2.4.20-pre2/fs/file_table.c linux-2.4.20-pre3/fs/file_table.c
--- linux-2.4.20-pre2/fs/file_table.c	Mon Sep 17 13:16:30 2001
+++ linux-2.4.20-pre3/fs/file_table.c	Sat Aug 17 14:18:59 2002
@@ -186,3 +186,17 @@
 	file_list_unlock();
 	return 0;
 }
+
+void __init files_init(unsigned long mempages)
+{ 
+	int n; 
+	/* One file with associated inode and dcache is very roughly 1K. 
+	 * Per default don't use more than 10% of our memory for files. 
+	 */ 
+
+	n = (mempages * (PAGE_SIZE / 1024)) / 10;
+	files_stat.max_files = n; 
+	if (files_stat.max_files < NR_FILE)
+		files_stat.max_files = NR_FILE;
+} 
+
diff -urN linux-2.4.20-pre2/fs/isofs/inode.c linux-2.4.20-pre3/fs/isofs/inode.c
--- linux-2.4.20-pre2/fs/isofs/inode.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre3/fs/isofs/inode.c	Sat Aug 17 14:18:59 2002
@@ -1283,6 +1283,15 @@
 	/* get the volume sequence number */
 	volume_seq_no = isonum_723 (de->volume_sequence_number) ;
 
+    /*
+     * Multi volume means tagging a group of CDs with info in their headers.
+     * All CDs of a group must share the same vol set name and vol set size
+     * and have different vol set seq num. Deciding that data is wrong based
+     * in that three fields is wrong. The fields are informative, for
+     * cataloging purposes in a big jukebox, ie. Read sections 4.17, 4.18, 6.6
+     * of ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf (ECMA 119 2nd Ed = ISO 9660)
+     */
+#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 	/*
 	 * Disable checking if we see any volume number other than 0 or 1.
 	 * We could use the cruft option, but that has multiple purposes, one
@@ -1296,6 +1305,7 @@
 		       "Enabling \"cruft\" mount option.\n", volume_seq_no);
 		inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
+#endif /*IGNORE_WRONG_MULTI_VOLUME_SPECS */
 
 	/* Install the inode operations vector */
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
diff -urN linux-2.4.20-pre2/fs/jbd/journal.c linux-2.4.20-pre3/fs/jbd/journal.c
--- linux-2.4.20-pre2/fs/jbd/journal.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/jbd/journal.c	Sat Aug 17 14:18:59 2002
@@ -462,8 +462,7 @@
 			printk (KERN_NOTICE "%s: ENOMEM at "
 				"get_unused_buffer_head, trying again.\n",
 				__FUNCTION__);
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		}
 	} while (!new_bh);
 	/* keep subsequent assertions sane */
@@ -1541,8 +1540,7 @@
 			last_warning = jiffies;
 		}
 		
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	}
 }
 
@@ -1600,8 +1598,7 @@
 			last_warning = jiffies;
 		}
 		while (ret == 0) {
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 			ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);
 		}
 	}
diff -urN linux-2.4.20-pre2/fs/jbd/revoke.c linux-2.4.20-pre3/fs/jbd/revoke.c
--- linux-2.4.20-pre2/fs/jbd/revoke.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre3/fs/jbd/revoke.c	Sat Aug 17 14:18:59 2002
@@ -137,8 +137,7 @@
 	if (!journal_oom_retry)
 		return -ENOMEM;
 	jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n");
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	goto repeat;
 }
 
diff -urN linux-2.4.20-pre2/fs/jbd/transaction.c linux-2.4.20-pre3/fs/jbd/transaction.c
--- linux-2.4.20-pre2/fs/jbd/transaction.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/jbd/transaction.c	Sat Aug 17 14:18:59 2002
@@ -1379,9 +1379,7 @@
 	if (handle->h_sync) {
 		do {
 			old_handle_count = transaction->t_handle_count;
-			set_current_state(TASK_RUNNING);
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} while (old_handle_count != transaction->t_handle_count);
 	}
 
diff -urN linux-2.4.20-pre2/fs/locks.c linux-2.4.20-pre3/fs/locks.c
--- linux-2.4.20-pre2/fs/locks.c	Thu Oct 11 07:52:18 2001
+++ linux-2.4.20-pre3/fs/locks.c	Sat Aug 17 14:18:59 2002
@@ -121,6 +121,7 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/sched.h>
+#include <linux/timer.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -445,8 +446,7 @@
 			/* Let the blocked process remove waiter from the
 			 * block list when it gets scheduled.
 			 */
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} else {
 			/* Remove waiter from the block list, because by the
 			 * time it wakes up blocker won't exist any more.
@@ -1051,6 +1051,47 @@
 	return -EINVAL;
 }
 
+/* We already had a lease on this file; just change its type */
+static int lease_modify(struct file_lock **before, int arg)
+{
+	struct file_lock *fl = *before;
+	int error = assign_type(fl, arg);
+
+	if (error)
+		return error;
+	locks_wake_up_blocks(fl, 0);
+	if (arg == F_UNLCK) {
+		struct file *filp = fl->fl_file;
+
+		filp->f_owner.pid = 0;
+		filp->f_owner.uid = 0;
+		filp->f_owner.euid = 0;
+		filp->f_owner.signum = 0;
+		locks_delete_lock(before, 0);
+	}
+	return 0;
+}
+
+static void time_out_leases(struct inode *inode)
+{
+	struct file_lock **before;
+	struct file_lock *fl;
+
+	before = &inode->i_flock;
+	while ((fl = *before) && (fl->fl_flags & FL_LEASE)
+			&& (fl->fl_type & F_INPROGRESS)) {
+		if ((fl->fl_break_time == 0)
+				|| time_before(jiffies, fl->fl_break_time)) {
+			before = &fl->fl_next;
+			continue;
+		}
+		printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid);
+		lease_modify(before, fl->fl_type & ~F_INPROGRESS);
+		if (fl == *before)	/* lease_modify may have freed fl */
+			before = &fl->fl_next;
+	}
+}
+
 /**
  *	__get_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
@@ -1067,34 +1108,30 @@
 	struct file_lock *new_fl, *flock;
 	struct file_lock *fl;
 	int alloc_err;
+	unsigned long break_time;
+	int i_have_this_lease = 0;
 
-	alloc_err = lease_alloc(NULL, 0, &new_fl);
+	alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK,
+			&new_fl);
 
 	lock_kernel();
+
+	time_out_leases(inode);
+
 	flock = inode->i_flock;
-	if (flock->fl_type & F_INPROGRESS) {
-		if ((mode & O_NONBLOCK)
-		    || (flock->fl_owner == current->files)) {
-			error = -EWOULDBLOCK;
-			goto out;
-		}
-		if (alloc_err != 0) {
-			error = alloc_err;
-			goto out;
-		}
-		do {
-			error = locks_block_on(flock, new_fl);
-			if (error != 0)
-				goto out;
-			flock = inode->i_flock;
-			if (!(flock && (flock->fl_flags & FL_LEASE)))
-				goto out;
-		} while (flock->fl_type & F_INPROGRESS);
-	}
+	if ((flock == NULL) || (flock->fl_flags & FL_LEASE) == 0)
+		goto out;
+
+	for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next)
+		if (fl->fl_owner == current->files)
+			i_have_this_lease = 1;
 
 	if (mode & FMODE_WRITE) {
 		/* If we want write access, we have to revoke any lease. */
 		future = F_UNLCK | F_INPROGRESS;
+	} else if (flock->fl_type & F_INPROGRESS) {
+		/* If the lease is already being broken, we just leave it */
+		future = flock->fl_type;
 	} else if (flock->fl_type & F_WRLCK) {
 		/* Downgrade the exclusive lease to a read-only lease. */
 		future = F_RDLCK | F_INPROGRESS;
@@ -1103,38 +1140,49 @@
 		goto out;
 	}
 
-	if (alloc_err && (flock->fl_owner != current->files)) {
+	if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) {
 		error = alloc_err;
 		goto out;
 	}
 
-	fl = flock;
-	do {
-		fl->fl_type = future;
-		fl = fl->fl_next;
-	} while (fl != NULL && (fl->fl_flags & FL_LEASE));
+	break_time = 0;
+	if (lease_break_time > 0) {
+		break_time = jiffies + lease_break_time * HZ;
+		if (break_time == 0)
+			break_time++;	/* so that 0 means no break time */
+	}
 
-	kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG);
+	for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next) {
+		if (fl->fl_type != future) {
+			fl->fl_type = future;
+			fl->fl_break_time = break_time;
+			kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
+		}
+	}
 
-	if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) {
+	if (i_have_this_lease || (mode & O_NONBLOCK)) {
 		error = -EWOULDBLOCK;
 		goto out;
 	}
 
-	if (lease_break_time > 0)
-		error = lease_break_time * HZ;
-	else
-		error = 0;
 restart:
-	error = locks_block_on_timeout(flock, new_fl, error);
-	if (error == 0) {
-		/* We timed out.  Unilaterally break the lease. */
-		locks_delete_lock(&inode->i_flock, 0);
-		printk(KERN_WARNING "lease timed out\n");
-	} else if (error > 0) {
-		flock = inode->i_flock;
-		if (flock && (flock->fl_flags & FL_LEASE))
-			goto restart;
+	break_time = flock->fl_break_time;
+	if (break_time != 0) {
+		break_time -= jiffies;
+		if (break_time == 0)
+			break_time++;
+	}
+	error = locks_block_on_timeout(flock, new_fl, break_time);
+	if (error >= 0) {
+		if (error == 0)
+			time_out_leases(inode);
+		/* Wait for the next lease that has not been broken yet */
+		for (flock = inode->i_flock;
+				flock && (flock->fl_flags & FL_LEASE);
+				flock = flock->fl_next) {
+			if (flock->fl_type & F_INPROGRESS)
+				goto restart;
+		}
 		error = 0;
 	}
 
@@ -1166,45 +1214,41 @@
  *	@filp: the file
  *
  *	The value returned by this function will be one of
+ *	(if no lease break is pending):
  *
- *	%F_RDLCK to indicate a read-only (type II) lease is held.
+ *	%F_RDLCK to indicate a shared lease is held.
  *
  *	%F_WRLCK to indicate an exclusive lease is held.
  *
- *	XXX: sfr & i disagree over whether F_INPROGRESS
+ *	%F_UNLCK to indicate no lease is held.
+ *
+ *	(if a lease break is pending):
+ *
+ *	%F_RDLCK to indicate an exclusive lease needs to be
+ *		changed to a shared lease (or removed).
+ *
+ *	%F_UNLCK to indicate the lease needs to be removed.
+ *
+ *	XXX: sfr & willy disagree over whether F_INPROGRESS
  *	should be returned to userspace.
  */
 int fcntl_getlease(struct file *filp)
 {
 	struct file_lock *fl;
-	
-	fl = filp->f_dentry->d_inode->i_flock;
-	if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0))
-		return F_UNLCK;
-	return fl->fl_type & ~F_INPROGRESS;
-}
+	int type = F_UNLCK;
 
-/* We already had a lease on this file; just change its type */
-static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp)
-{
-	struct file_lock *fl = *before;
-	int error = assign_type(fl, arg);
-	if (error < 0)
-		goto out;
-
-	locks_wake_up_blocks(fl, 0);
-
-	if (arg == F_UNLCK) {
-		filp->f_owner.pid = 0;
-		filp->f_owner.uid = 0;
-		filp->f_owner.euid = 0;
-		filp->f_owner.signum = 0;
-		locks_delete_lock(before, 0);
-		fasync_helper(fd, filp, 0, &fl->fl_fasync);
+	lock_kernel();
+	time_out_leases(filp->f_dentry->d_inode);
+	for (fl = filp->f_dentry->d_inode->i_flock;
+			fl && (fl->fl_flags & FL_LEASE);
+			fl = fl->fl_next) {
+		if (fl->fl_file == filp) {
+			type = fl->fl_type & ~F_INPROGRESS;
+			break;
+		}
 	}
-
-out:
-	return error;
+	unlock_kernel();
+	return type;
 }
 
 /**
@@ -1232,50 +1276,59 @@
 	if (!S_ISREG(inode->i_mode))
 		return -EINVAL;
 
+	lock_kernel();
+
+	time_out_leases(inode);
+
 	/*
 	 * FIXME: What about F_RDLCK and files open for writing?
 	 */
+	error = -EAGAIN;
 	if ((arg == F_WRLCK)
 	    && ((atomic_read(&dentry->d_count) > 1)
 		|| (atomic_read(&inode->i_count) > 1)))
-		return -EAGAIN;
-
-	before = &inode->i_flock;
-
-	lock_kernel();
+		goto out_unlock;
 
-	while ((fl = *before) != NULL) {
-		if (fl->fl_flags != FL_LEASE)
-			break;
+	/*
+	 * At this point, we know that if there is an exclusive
+	 * lease on this file, then we hold it on this filp
+	 * (otherwise our open of this file would have blocked).
+	 * And if we are trying to acquire an exclusive lease,
+	 * then the file is not open by anyone (including us)
+	 * except for this filp.
+	 */
+	for (before = &inode->i_flock;
+			((fl = *before) != NULL) && (fl->fl_flags & FL_LEASE);
+			before = &fl->fl_next) {
 		if (fl->fl_file == filp)
 			my_before = before;
-		else if (fl->fl_type & F_WRLCK)
+		else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
+			/*
+			 * Someone is in the process of opening this
+			 * file for writing so we may not take an
+			 * exclusive lease on it.
+			 */
 			wrlease_count++;
 		else
 			rdlease_count++;
-		before = &fl->fl_next;
 	}
 
 	if ((arg == F_RDLCK && (wrlease_count > 0)) ||
-	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) {
-		error = -EAGAIN;
+	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
 		goto out_unlock;
-	}
 
 	if (my_before != NULL) {
-		error = lease_modify(my_before, arg, fd, filp);
+		error = lease_modify(my_before, arg);
 		goto out_unlock;
 	}
 
-	if (arg == F_UNLCK) {
-		error = 0;
+	error = 0;
+	if (arg == F_UNLCK)
 		goto out_unlock;
-	}
 
-	if (!leases_enable) {
-		error = -EINVAL;
+	error = -EINVAL;
+	if (!leases_enable)
 		goto out_unlock;
-	}
 
 	error = lease_alloc(filp, arg, &fl);
 	if (error)
@@ -1710,10 +1763,15 @@
 	before = &inode->i_flock;
 
 	while ((fl = *before) != NULL) {
-		if ((fl->fl_flags & (FL_FLOCK|FL_LEASE))
-		    && (fl->fl_file == filp)) {
-			locks_delete_lock(before, 0);
-			continue;
+		if (fl->fl_file == filp) {
+			if (fl->fl_flags & FL_FLOCK) {
+				locks_delete_lock(before, 0);
+				continue;
+			}
+			if (fl->fl_flags & FL_LEASE) {
+				lease_modify(before, F_UNLCK);
+				continue;
+			}
  		}
 		before = &fl->fl_next;
 	}
@@ -1769,7 +1827,13 @@
 #endif
 			out += sprintf(out, "FLOCK  ADVISORY  ");
 	} else if (fl->fl_flags & FL_LEASE) {
-		out += sprintf(out, "LEASE  MANDATORY ");
+		out += sprintf(out, "LEASE  ");
+		if (fl->fl_type & F_INPROGRESS)
+			out += sprintf(out, "BREAKING  ");
+		else if (fl->fl_file)
+			out += sprintf(out, "ACTIVE    ");
+		else
+			out += sprintf(out, "BREAKER   ");
 	} else {
 		out += sprintf(out, "UNKNOWN UNKNOWN  ");
 	}
@@ -1782,7 +1846,9 @@
 	} else
 #endif
 		out += sprintf(out, "%s ",
-			       (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+			       (fl->fl_type & F_INPROGRESS)
+			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
+			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
 	out += sprintf(out, "%d %s:%ld ",
 		     fl->fl_pid,
 		     inode ? kdevname(inode->i_dev) : "<none>",
@@ -1940,7 +2006,7 @@
 
 static int __init filelock_init(void)
 {
-	filelock_cache = kmem_cache_create("file lock cache",
+	filelock_cache = kmem_cache_create("file_lock_cache",
 			sizeof(struct file_lock), 0, 0, init_once, NULL);
 	if (!filelock_cache)
 		panic("cannot create file lock slab cache");
diff -urN linux-2.4.20-pre2/fs/nfs/dir.c linux-2.4.20-pre3/fs/nfs/dir.c
--- linux-2.4.20-pre2/fs/nfs/dir.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/nfs/dir.c	Sat Aug 17 14:18:59 2002
@@ -45,12 +45,14 @@
 static int nfs_mknod(struct inode *, struct dentry *, int, int);
 static int nfs_rename(struct inode *, struct dentry *,
 		      struct inode *, struct dentry *);
+static int nfs_fsync_dir(struct file *, struct dentry *, int);
 
 struct file_operations nfs_dir_operations = {
 	read:		generic_read_dir,
 	readdir:	nfs_readdir,
 	open:		nfs_open,
 	release:	nfs_release,
+	fsync:		nfs_fsync_dir
 };
 
 struct inode_operations nfs_dir_inode_operations = {
@@ -99,13 +101,12 @@
 	struct file	*file = desc->file;
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
-	void		*buffer = kmap(page);
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
-	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
+	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
@@ -116,7 +117,6 @@
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	/* Ensure consistent page alignment of the data.
 	 * Note: assumes we have exclusive access to this mapping either
 	 *	 throught inode->i_sem or some other mechanism.
@@ -315,12 +315,12 @@
 		status = -ENOMEM;
 		goto out;
 	}
-	desc->page = page;
-	desc->ptr = kmap(page);
 	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,
-						desc->ptr,
+						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
+	desc->page = page;
+	desc->ptr = kmap(page);
 	if (desc->error >= 0) {
 		if ((status = dir_decode(desc)) == 0)
 			desc->entry->prev_cookie = desc->target;
@@ -401,6 +401,15 @@
 	return 0;
 }
 
+/*
+ * All directory operations under NFS are synchronous, so fsync()
+ * is a dummy operation.
+ */
+int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
+{
+	return 0;
+}
+
 /*
  * A check for whether or not the parent directory has changed.
  * In the case it has, we assume that the dentries are untrustworthy
diff -urN linux-2.4.20-pre2/fs/nfs/nfs2xdr.c linux-2.4.20-pre3/fs/nfs/nfs2xdr.c
--- linux-2.4.20-pre2/fs/nfs/nfs2xdr.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre3/fs/nfs/nfs2xdr.c	Sat Aug 17 14:18:59 2002
@@ -24,9 +24,6 @@
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES 1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
@@ -90,17 +87,6 @@
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
 static inline u32*
 xdr_decode_time(u32 *p, u64 *timep)
 {
@@ -109,7 +95,7 @@
 	return p;
 }
 
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -223,35 +209,20 @@
 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 offset = (u32)args->offset;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
-	*p++ = htonl(args->count);
+	*p++ = htonl(offset);
+	*p++ = htonl(count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-        nr = args->nriov;
-
-        if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-                return -EINVAL;
-        }
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-        /* Copy the iovec */
-        memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -272,7 +243,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -284,7 +255,6 @@
 
 	dprintk("RPC:      readres OK count %d\n", count);
 	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
 		res->count = count;
 		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
 	} else
@@ -300,46 +270,19 @@
 static int
 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	u32 offset = (u32)args->offset;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->offset);
+	*p++ = htonl(offset);
+	*p++ = htonl(offset);
 	*p++ = htonl(count);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
-                        "(nr %d max %d)\n", nr, MAX_IOVEC);
-                return -EINVAL;
-        }
-
-	/* Copy the iovec */
-        memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -406,32 +349,24 @@
 {
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
-	u32		bufsiz = args->bufsiz;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	/*
 	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
 	 * to be in longwords ... check whether to convert the size.
 	 */
 	if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
-		bufsiz = bufsiz >> 2;
+		count = count >> 2;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->cookie);
-	*p++ = htonl(bufsiz); /* see above */
+	*p++ = htonl(count); /* see above */
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -443,12 +378,15 @@
  * from nfs_readdir for each entry.
  */
 static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
+nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec		*iov = req->rq_rvec;
-	int			 hdrlen;
-	int			 status, nr;
-	u32			*end, *entry, len;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *end, *entry;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
@@ -456,13 +394,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-
-	/* Get start and end address of XDR data */
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 2 > end)
@@ -473,16 +411,21 @@
 		if (len > NFS2_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 		if (p + 2 > end)
 			goto short_pkt;
 	}
+	kunmap(*page);
 	return nr;
  short_pkt:
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	entry[0] = entry[1] = 0;
+	kunmap(*page);
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -568,21 +511,16 @@
 static int
 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -590,32 +528,33 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec *iov = req->rq_rvec;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
-	int	hdrlen;
 	int	status;
-	unsigned int len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
diff -urN linux-2.4.20-pre2/fs/nfs/nfs3proc.c linux-2.4.20-pre3/fs/nfs/nfs3proc.c
--- linux-2.4.20-pre2/fs/nfs/nfs3proc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/nfs/nfs3proc.c	Sat Aug 17 14:18:59 2002
@@ -151,17 +151,16 @@
 }
 
 static int
-nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, struct page *page)
 {
 	struct nfs_fattr	fattr;
-	struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen };
-	struct nfs3_readlinkres	res = { &fattr, buffer, buflen };
+	struct nfs3_readlinkargs args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
 	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
-			  &args, &res, 0);
+			&args, &fattr, 0);
 	nfs_refresh_inode(inode, &fattr);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
@@ -170,11 +169,12 @@
 static int
 nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int flags,
-	       loff_t offset, unsigned int count, void *buffer, int *eofp)
+	       unsigned int base, unsigned int count, struct page *page,
+	       int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	u64			offset = page_offset(page) + base;
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count,
+					base, &page };
 	struct nfs_readres	res = { fattr, count, 0 };
 	struct rpc_message	msg = { NFS3PROC_READ, &arg, &res, cred };
 	int			status;
@@ -190,13 +190,12 @@
 static int
 nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
 		struct nfs_fattr *fattr, int flags,
-		loff_t offset, unsigned int count,
-		void *buffer, struct nfs_writeverf *verf)
+		unsigned int base, unsigned int count,
+		struct page *page, struct nfs_writeverf *verf)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
-					NFS_FILE_SYNC, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}} };
+					NFS_FILE_SYNC, base, &page };
 	struct nfs_writeres	res = { fattr, verf, 0 };
 	struct rpc_message	msg = { NFS3PROC_WRITE, &arg, &res, cred };
 	int			status, rpcflags = 0;
@@ -434,26 +433,16 @@
  */
 static int
 nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		  u64 cookie, void *entry,
-		  unsigned int size, int plus)
+		  u64 cookie, struct page *page, unsigned int count, int plus)
 {
 	struct nfs_fattr	dir_attr;
-	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
-	struct nfs3_readdirres	res = { &dir_attr, 0, 0, 0, 0 };
-	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
 	u32			*verf = NFS_COOKIEVERF(dir);
+	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {verf[0], verf[1]},
+	       				plus, count, &page };
+	struct nfs3_readdirres	res = { &dir_attr, verf, plus };
+	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
 	int			status;
 
-	arg.buffer  = entry;
-	arg.bufsiz  = size;
-	arg.verf[0] = verf[0];
-	arg.verf[1] = verf[1];
-	arg.plus    = plus;
-	res.buffer  = entry;
-	res.bufsiz  = size;
-	res.verf    = verf;
-	res.plus    = plus;
-
 	if (plus)
 		msg.rpc_proc = NFS3PROC_READDIRPLUS;
 
diff -urN linux-2.4.20-pre2/fs/nfs/nfs3xdr.c linux-2.4.20-pre3/fs/nfs/nfs3xdr.c
--- linux-2.4.20-pre2/fs/nfs/nfs3xdr.c	Fri Nov  2 17:40:09 2001
+++ linux-2.4.20-pre3/fs/nfs/nfs3xdr.c	Sat Aug 17 14:18:59 2002
@@ -22,9 +22,6 @@
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES		1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
@@ -156,18 +153,7 @@
 	return p;
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	unsigned int	type;
@@ -350,35 +336,18 @@
 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->offset);
-	*p++ = htonl(args->count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-		return -EINVAL;
-	}
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-
-	/* Copy the iovec */
-	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -388,7 +357,7 @@
 static int
 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int	nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
@@ -396,37 +365,10 @@
 	*p++ = htonl(count);
 	*p++ = htonl(args->stable);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
-		return -EINVAL;
-	}
-
-	/* Copy the iovec */
-	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr  += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -530,7 +472,8 @@
 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->cookie);
@@ -539,22 +482,14 @@
 	if (args->plus) {
 		/* readdirplus: need dircount + buffer size.
 		 * We just make sure we make dircount big enough */
-		*p++ = htonl(args->bufsiz >> 3);
+		*p++ = htonl(count >> 3);
 	}
-	*p++ = htonl(args->bufsiz);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -565,11 +500,13 @@
 static int
 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	int		status, nr;
-	unsigned int	len;
-	u32		*entry, *end;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *entry, *end;
 
 	status = ntohl(*p++);
 	/* Decode post_op_attrs */
@@ -587,11 +524,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 3 > end)
@@ -602,7 +541,7 @@
 		if (len > NFS3_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 
 		if (res->plus) {
@@ -622,7 +561,7 @@
 				if (len > NFS3_FHSIZE) {
 					printk(KERN_WARNING "NFS: giant filehandle in "
 						"readdir (len %x)!\n", len);
-					return -errno_NFSERR_IO;
+					goto err_unmap;
 				}
 				p += XDR_QUADLEN(len);
 			}
@@ -631,13 +570,17 @@
 		if (p + 2 > end)
 			goto short_pkt;
 	}
-
+	kunmap(*page);
 	return nr;
  short_pkt:
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	/* truncate listing */
 	entry[0] = entry[1] = 0;
+	kunmap(*page);
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -772,21 +715,16 @@
 static int
 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -794,17 +732,17 @@
  * Decode READLINK reply
  */
 static int
-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
 	int	status;
-	unsigned int len;
 
 	status = ntohl(*p++);
-	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_post_op_attr(p, fattr);
 
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
@@ -812,18 +750,19 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
@@ -857,7 +796,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -867,10 +806,8 @@
 		count = recvd;
 	}
 
-	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+	if (count < res->count)
 		res->count = count;
-	}
 
 	return count;
 }
diff -urN linux-2.4.20-pre2/fs/nfs/pagelist.c linux-2.4.20-pre3/fs/nfs/pagelist.c
--- linux-2.4.20-pre2/fs/nfs/pagelist.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/nfs/pagelist.c	Sat Aug 17 14:18:59 2002
@@ -96,8 +96,7 @@
 			continue;
 		if (signalled() && (server->flags & NFS_MOUNT_INTR))
 			return ERR_PTR(-ERESTARTSYS);
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	}
 
 	/* Initialize the request struct. Initially, we assume a
diff -urN linux-2.4.20-pre2/fs/nfs/proc.c linux-2.4.20-pre3/fs/nfs/proc.c
--- linux-2.4.20-pre2/fs/nfs/proc.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre3/fs/nfs/proc.c	Sat Aug 17 14:18:59 2002
@@ -106,15 +106,13 @@
 }
 
 static int
-nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, struct page *page)
 {
-	struct nfs_readlinkargs	args = { NFS_FH(inode), buffer, bufsiz };
-	struct nfs_readlinkres	res = { buffer, bufsiz };
+	struct nfs_readlinkargs	args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
-					&args, &res, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
@@ -122,11 +120,12 @@
 static int
 nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
 	      struct nfs_fattr *fattr, int flags,
-	      loff_t offset, unsigned int count, void *buffer, int *eofp)
+	      unsigned int base, unsigned int count,
+	      struct page *page, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
-				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
-					{0,0}, {0,0}, {0,0}, {0,0}} };
+	u64			offset = page_offset(page) + base;
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count,
+					base, &page };
 	struct nfs_readres	res = { fattr, count, 0};
 	struct rpc_message	msg = { NFSPROC_READ, &arg, &res, cred };
 	int			status;
@@ -143,13 +142,12 @@
 static int
 nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int how,
-	       loff_t offset, unsigned int count,
-	       void *buffer, struct nfs_writeverf *verf)
+	       unsigned int base, unsigned int count,
+	       struct page *page, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = {NFS_FH(inode), offset, count,
-					NFS_FILE_SYNC, 1,
-					{{buffer, count}, {0,0}, {0,0}, {0,0},
-					 {0,0}, {0,0}, {0,0}, {0,0}}};
+	u64			offset = page_offset(page) + base;
+	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
+					NFS_FILE_SYNC, base, &page };
 	struct nfs_writeres     res = {fattr, verf, count};
 	struct rpc_message	msg = { NFSPROC_WRITE, &arg, &res, cred };
 	int			status, flags = 0;
@@ -337,21 +335,13 @@
  */
 static int
 nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		 __u64 cookie, void *entry, 
-		 unsigned int size, int plus)
+		 __u64 cookie, struct page *page, 
+		 unsigned int count, int plus)
 {
-	struct nfs_readdirargs	arg;
-	struct nfs_readdirres	res;
-	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, cred };
+	struct nfs_readdirargs	arg = { NFS_FH(dir), cookie, count, &page };
+	struct rpc_message	msg = { NFSPROC_READDIR, &arg, NULL, cred };
 	int			status;
 
-	arg.fh = NFS_FH(dir);
-	arg.cookie = cookie;
-	arg.buffer = entry;
-	arg.bufsiz = size;
-	res.buffer = entry;
-	res.bufsiz = size;
-
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
diff -urN linux-2.4.20-pre2/fs/nfs/read.c linux-2.4.20-pre3/fs/nfs/read.c
--- linux-2.4.20-pre2/fs/nfs/read.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/nfs/read.c	Sat Aug 17 14:18:59 2002
@@ -42,6 +42,7 @@
 	struct nfs_readres	res;	/* ... and result struct */
 	struct nfs_fattr	fattr;	/* fattr storage */
 	struct list_head	pages;	/* Coalesced read requests */
+	struct page		*pagevec[NFS_READ_MAXIOV];
 };
 
 /*
@@ -63,6 +64,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -86,8 +88,7 @@
 {
 	struct rpc_cred	*cred = NULL;
 	struct nfs_fattr fattr;
-	loff_t		offset = page_offset(page);
-	char		*buffer;
+	unsigned int	offset = 0;
 	int		rsize = NFS_SERVER(inode)->rsize;
 	int		result;
 	int		count = PAGE_CACHE_SIZE;
@@ -103,19 +104,18 @@
 	 * This works now because the socket layer never tries to DMA
 	 * into this buffer directly.
 	 */
-	buffer = kmap(page);
 	do {
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %u, %u, %p)\n",
 			NFS_SERVER(inode)->hostname,
 			inode->i_dev, (long long)NFS_FILEID(inode),
-			(long long)offset, rsize, buffer);
+			offset, rsize, page);
 
 		lock_kernel();
 		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
-						offset, rsize, buffer, &eof);
+						offset, rsize, page, &eof);
 		nfs_refresh_inode(inode, &fattr);
 		unlock_kernel();
 
@@ -130,12 +130,15 @@
 		}
 		count  -= result;
 		offset += result;
-		buffer += result;
 		if (result < rsize)	/* NFSv2ism */
 			break;
 	} while (count);
 
-	memset(buffer, 0, count);
+	if (count) {
+		char *kaddr = kmap(page);
+		memset(kaddr + offset, 0, count);
+		kunmap(page);
+	}
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	if (PageError(page))
@@ -143,7 +146,6 @@
 	result = 0;
 
 io_error:
-	kunmap(page);
 	UnlockPage(page);
 	return result;
 }
@@ -186,26 +188,24 @@
 nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode	  = req->wb_inode;
 	data->cred	  = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -266,10 +266,10 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x/%Ld count %u.\n",
 		task->tk_pid,
 		inode->i_dev, (long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		data->args.count);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -424,7 +424,6 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
-		kunmap(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
diff -urN linux-2.4.20-pre2/fs/nfs/symlink.c linux-2.4.20-pre3/fs/nfs/symlink.c
--- linux-2.4.20-pre2/fs/nfs/symlink.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre3/fs/nfs/symlink.c	Sat Aug 17 14:18:59 2002
@@ -29,7 +29,6 @@
  */
 static int nfs_symlink_filler(struct inode *inode, struct page *page)
 {
-	void *buffer = kmap(page);
 	int error;
 
 	/* We place the length at the beginning of the page,
@@ -37,13 +36,11 @@
 	 * XDR response verification will NULL terminate it.
 	 */
 	lock_kernel();
-	error = NFS_PROTO(inode)->readlink(inode, buffer,
-					   PAGE_CACHE_SIZE - sizeof(u32)-4);
+	error = NFS_PROTO(inode)->readlink(inode, page);
 	unlock_kernel();
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	UnlockPage(page);
 	return 0;
 
diff -urN linux-2.4.20-pre2/fs/nfs/write.c linux-2.4.20-pre3/fs/nfs/write.c
--- linux-2.4.20-pre2/fs/nfs/write.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/nfs/write.c	Sat Aug 17 14:18:59 2002
@@ -77,6 +77,7 @@
 	struct nfs_fattr	fattr;
 	struct nfs_writeverf	verf;
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
+	struct page		*pagevec[NFS_WRITE_MAXIOV];
 };
 
 /*
@@ -105,6 +106,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -163,7 +165,6 @@
 		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
-	buffer = kmap(page) + offset;
 	base = page_offset(page) + offset;
 
 	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
@@ -173,7 +174,7 @@
 			wsize = count;
 
 		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
-						 base, wsize, buffer, &verf);
+						 offset, wsize, page, &verf);
 		nfs_write_attributes(inode, &fattr);
 
 		if (result < 0) {
@@ -186,7 +187,8 @@
 			wsize, result);
 		refresh = 1;
 		buffer  += wsize;
-	        base    += wsize;
+		base    += wsize;
+	        offset  += wsize;
 		written += wsize;
 		count   -= wsize;
 		/*
@@ -201,7 +203,6 @@
 		ClearPageError(page);
 
 io_error:
-	kunmap(page);
 	if (cred)
 		put_rpccred(cred);
 
@@ -861,29 +862,27 @@
 nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -948,11 +947,11 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x/%Ld count %u)\n",
 		task->tk_pid, 
 		inode->i_dev,
 		(long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		data->args.count);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -1064,8 +1063,6 @@
 		nfs_list_remove_request(req);
 		page = req->wb_page;
 
-		kunmap(page);
-
 		dprintk("NFS: write (%x/%Ld %d@%Ld)",
 			req->wb_inode->i_dev,
 			(long long)NFS_FILEID(req->wb_inode),
diff -urN linux-2.4.20-pre2/fs/nfsd/nfssvc.c linux-2.4.20-pre3/fs/nfsd/nfssvc.c
--- linux-2.4.20-pre2/fs/nfsd/nfssvc.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/nfsd/nfssvc.c	Sat Aug 17 14:18:59 2002
@@ -95,7 +95,7 @@
 		if (error < 0)
 			goto failure;
 
-#if 0	/* Don't even pretend that TCP works. It doesn't. */
+#if CONFIG_NFSD_TCP
 		error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
 		if (error < 0)
 			goto failure;
diff -urN linux-2.4.20-pre2/fs/nls/Makefile linux-2.4.20-pre3/fs/nls/Makefile
--- linux-2.4.20-pre2/fs/nls/Makefile	Sat May 19 17:47:55 2001
+++ linux-2.4.20-pre3/fs/nls/Makefile	Sat Aug 17 14:18:59 2002
@@ -29,12 +29,6 @@
 obj-$(CONFIG_NLS_CODEPAGE_950)	+= nls_cp950.o nls_big5.o
 obj-$(CONFIG_NLS_CODEPAGE_1250)	+= nls_cp1250.o
 obj-$(CONFIG_NLS_CODEPAGE_1251)	+= nls_cp1251.o
-obj-$(CONFIG_NLS_CODEPAGE_1252)	+= nls_cp1252.o
-obj-$(CONFIG_NLS_CODEPAGE_1253)	+= nls_cp1253.o
-obj-$(CONFIG_NLS_CODEPAGE_1254)	+= nls_cp1254.o
-obj-$(CONFIG_NLS_CODEPAGE_1256)	+= nls_cp1256.o
-obj-$(CONFIG_NLS_CODEPAGE_1257)	+= nls_cp1257.o
-obj-$(CONFIG_NLS_CODEPAGE_1258)	+= nls_cp1258.o
 obj-$(CONFIG_NLS_ISO8859_1)	+= nls_iso8859-1.o
 obj-$(CONFIG_NLS_ISO8859_2)	+= nls_iso8859-2.o
 obj-$(CONFIG_NLS_ISO8859_3)	+= nls_iso8859-3.o
@@ -44,13 +38,11 @@
 obj-$(CONFIG_NLS_ISO8859_7)	+= nls_iso8859-7.o
 obj-$(CONFIG_NLS_ISO8859_8)	+= nls_cp1255.o nls_iso8859-8.o
 obj-$(CONFIG_NLS_ISO8859_9)	+= nls_iso8859-9.o
-obj-$(CONFIG_NLS_ISO8859_10)	+= nls_iso8859-10.o
 obj-$(CONFIG_NLS_ISO8859_13)	+= nls_iso8859-13.o
 obj-$(CONFIG_NLS_ISO8859_14)	+= nls_iso8859-14.o
 obj-$(CONFIG_NLS_ISO8859_15)	+= nls_iso8859-15.o
 obj-$(CONFIG_NLS_KOI8_R)	+= nls_koi8-r.o
 obj-$(CONFIG_NLS_KOI8_U)	+= nls_koi8-u.o nls_koi8-ru.o
-obj-$(CONFIG_NLS_ABC)		+= nls_abc.o
 obj-$(CONFIG_NLS_UTF8)		+= nls_utf8.o
 
 export-objs = $(obj-y)
diff -urN linux-2.4.20-pre2/fs/nls/nls_cp1250.c linux-2.4.20-pre3/fs/nls/nls_cp1250.c
--- linux-2.4.20-pre2/fs/nls/nls_cp1250.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre3/fs/nls/nls_cp1250.c	Sat Aug 17 14:18:59 2002
@@ -344,7 +344,7 @@
 module_init(init_nls_cp1250)
 module_exit(exit_nls_cp1250)
 
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.4.20-pre2/fs/partitions/efi.c linux-2.4.20-pre3/fs/partitions/efi.c
--- linux-2.4.20-pre2/fs/partitions/efi.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/partitions/efi.c	Sat Aug 17 14:18:59 2002
@@ -740,7 +740,7 @@
                                  PARTITION_LINUX_RAID_GUID)) {
                         md_autodetect_dev(MKDEV
                                           (MAJOR(to_kdev_t(bdev->bd_dev)),
-                                           nextminor));
+                                           nextminor+i));
 		}
 #endif
 	}
diff -urN linux-2.4.20-pre2/fs/partitions/ldm.c linux-2.4.20-pre3/fs/partitions/ldm.c
--- linux-2.4.20-pre2/fs/partitions/ldm.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/partitions/ldm.c	Sat Aug 17 14:18:59 2002
@@ -1,1074 +1,1543 @@
-/*
- * ldm - Part of the Linux-NTFS project.
+/**
+ * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
  *
- * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net> (AIA)
+ * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ * Copyright (C) 2001      Anton Altaparmakov <aia21@cantab.net>
+ * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
- * 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 (in the main directory of the Linux-NTFS source
- * in the file COPYING); if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * 28/10/2001 - Added sorting of ldm partitions. (AIA)
- */
-#include <linux/types.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/genhd.h>
-#include <linux/blkdev.h>
+ * 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 (in the main directory of the source in the file COPYING); if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA  02111-1307  USA
+ */
+
 #include <linux/slab.h>
+#include <linux/stringify.h>
 #include <linux/pagemap.h>
-#include "check.h"
 #include "ldm.h"
+#include "check.h"
 #include "msdos.h"
 
-#if 0 /* Fool kernel-doc since it doesn't do macros yet. */
+typedef enum {
+	FALSE = 0,
+	TRUE  = 1
+} BOOL;
+
 /**
- * ldm_debug - output an error message if debugging was enabled at compile time
- * @f:		a printf format string containing the message
- * @...:	the variables to substitute into @f
+ * ldm_debug/info/error/crit - Output an error message
+ * @f:    A printf format string containing the message
+ * @...:  Variables to substitute into @f
  *
  * ldm_debug() writes a DEBUG level message to the syslog but only if the
  * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
  */
-static void ldm_debug(const char *f, ...);
+#ifndef CONFIG_LDM_DEBUG
+#define ldm_debug(...)	do {} while (0)
+#else
+#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a)
 #endif
-#ifdef CONFIG_LDM_DEBUG
-#define ldm_debug(f, a...)						\
-	{								\
-		printk(LDM_DEBUG " DEBUG (%s, %d): %s: ",		\
-				__FILE__, __LINE__, __FUNCTION__);	\
-		printk(f, ##a);						\
-	}
-#else	/* !CONFIG_LDM_DEBUG */
-#define ldm_debug(f, a...)	do {} while (0)
-#endif	/* !CONFIG_LDM_DEBUG */
 
-/* Necessary forward declarations. */
-static int create_partition(struct gendisk *, int, int, int);
-static int parse_privhead(const u8 *, struct privhead *);
-static u64 get_vnum(const u8 *, int *);
-static int get_vstr(const u8 *, u8 *, const int);
+#define ldm_crit(f, a...)  _ldm_printk (KERN_CRIT,  __FUNCTION__, f, ##a)
+#define ldm_error(f, a...) _ldm_printk (KERN_ERR,   __FUNCTION__, f, ##a)
+#define ldm_info(f, a...)  _ldm_printk (KERN_INFO,  __FUNCTION__, f, ##a)
+
+__attribute__ ((format (printf, 3, 4)))
+static void _ldm_printk (const char *level, const char *function,
+			 const char *fmt, ...)
+{
+	static char buf[128];
+	va_list args;
+
+	va_start (args, fmt);
+	vsnprintf (buf, sizeof (buf), fmt, args);
+	va_end (args);
+
+	printk ("%s%s(): %s\n", level, function, buf);
+}
+
 
 /**
- * parse_vblk_part - parse a LDM database vblk partition record
- * @buffer:	vblk partition record loaded from the LDM database
- * @buf_size:	size of @buffer in bytes
- * @vb:		in memory vblk structure to return parsed information in
+ * ldm_parse_hexbyte - Convert a ASCII hex number to a byte
+ * @src:  Pointer to at least 2 characters to convert.
  *
- * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
- * record, supplied in @buffer and sets up the in memory vblk structure @vb
- * with the obtained information.
+ * Convert a two character ASCII hex string to a number.
  *
- * Return 1 on success and -1 on error, in which case @vb is undefined.
+ * Return:  0-255  Success, the byte was parsed correctly
+ *          -1     Error, an invalid character was supplied
  */
-static int parse_vblk_part(const u8 *buffer, const int buf_size,
-		struct vblk *vb)
+static int ldm_parse_hexbyte (const u8 *src)
 {
-	int err, rel_objid, rel_name, rel_size, rel_parent;
+	unsigned int x;		/* For correct wrapping */
+	int h;
 
-	if (0x34 >= buf_size)
-		return -1;
-	/* Calculate relative offsets. */
-	rel_objid  = 1 + buffer[0x18];
-	if (0x18 + rel_objid >= buf_size)
-		return -1;
-	rel_name   = 1 + buffer[0x18 + rel_objid] + rel_objid;
-	if (0x34 + rel_name >= buf_size)
-		return -1;
-	rel_size   = 1 + buffer[0x34 + rel_name] + rel_name;
-	if (0x34 + rel_size >= buf_size)
-		return -1;
-	rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
-	if (0x34 + rel_parent >= buf_size)
-		return -1;
-	/* Setup @vb. */
-	vb->vblk_type    = VBLK_PART;
-	vb->obj_id       = get_vnum(buffer + 0x18, &err);
-	if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
-		return -1;
-	vb->disk_id      = get_vnum(buffer + 0x34 + rel_parent, &err);
-	if (err || 0x24 + rel_name + 8 > buf_size)
-		return -1;
-	vb->start_sector = BE64(buffer + 0x24 + rel_name);
-	if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
-		return -1;
-	vb->num_sectors  = get_vnum(buffer + 0x34 + rel_name, &err);
-	if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
-		return -1;
-	err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
-	if (err == -1)
-		return err;
-	ldm_debug("Parsed Partition VBLK successfully.\n");
-	return 1;
+	/* high part */
+	if      ((x = src[0] - '0') <= '9'-'0') h = x;
+	else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10;
+	else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10;
+	else return -1;
+	h <<= 4;
+
+	/* low part */
+	if ((x = src[1] - '0') <= '9'-'0') return h | x;
+	if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10);
+	if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10);
+	return -1;
 }
 
 /**
- * parse_vblk - parse a LDM database vblk record
- * @buffer:	vblk record loaded from the LDM database
- * @buf_size:	size of @buffer in bytes
- * @vb:		in memory vblk structure to return parsed information in
+ * ldm_parse_guid - Convert GUID from ASCII to binary
+ * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @dest:  Memory block to hold binary GUID (16 bytes)
+ *
+ * N.B. The GUID need not be NULL terminated.
  *
- * This parses the LDM database vblk record supplied in @buffer and sets up
- * the in memory vblk structure @vb with the obtained information.
+ * Return:  TRUE   @dest contains binary GUID
+ *          FALSE  @dest contents are undefined
+ */
+static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
+{
+	static const int size[] = { 4, 2, 2, 2, 6 };
+	int i, j, v;
+
+	if (src[8]  != '-' || src[13] != '-' ||
+	    src[18] != '-' || src[23] != '-')
+		return FALSE;
+
+	for (j = 0; j < 5; j++, src++)
+		for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
+			if ((v = ldm_parse_hexbyte (src)) < 0)
+				return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
+ * @data:  Raw database PRIVHEAD structure loaded from the device
+ * @ph:    In-memory privhead structure in which to return parsed information
  *
- * Return 1 on success, 0 if successful but record not in use, and -1 on error.
- * If the return value is 0 or -1, @vb is undefined.
+ * This parses the LDM database PRIVHEAD structure supplied in @data and
+ * sets up the in-memory privhead structure @ph with the obtained information.
  *
- * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
- * describing a partition. For all others, we just set @vb->vblk_type to 0 and
- * return success. This of course means that if @vb->vblk_type is zero, all
- * other fields in @vb are undefined.
+ * Return:  TRUE   @ph contains the PRIVHEAD data
+ *          FALSE  @ph contents are undefined
  */
-static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
+static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
 {
-	int err = 1;
+	BUG_ON (!data);
+	BUG_ON (!ph);
 
-	if (buf_size < 0x14)
-		return -1;
-	if (MAGIC_VBLK != BE32(buffer)) {
-		printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
-		return -1;
+	if (MAGIC_PRIVHEAD != BE64 (data)) {
+		ldm_error ("Cannot find PRIVHEAD structure. LDM database is"
+			" corrupt. Aborting.");
+		return FALSE;
 	}
-	if ((BE16(buffer + 0x0E) == 0) ||       /* Record is not in use. */
-	    (BE16(buffer + 0x0C) != 0))         /* Part 2 of an ext. record */
-		return 0;
-	/* FIXME: What about extended VBLKs? */
-	switch (buffer[0x13]) {
-	case VBLK_PART:
-		err = parse_vblk_part(buffer, buf_size, vb);
-		break;
-	default:
-		vb->vblk_type = 0;
+
+	ph->ver_major          = BE16 (data + 0x000C);
+	ph->ver_minor          = BE16 (data + 0x000E);
+	ph->logical_disk_start = BE64 (data + 0x011B);
+	ph->logical_disk_size  = BE64 (data + 0x0123);
+	ph->config_start       = BE64 (data + 0x012B);
+	ph->config_size        = BE64 (data + 0x0133);
+
+	if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+		ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d."
+			" Aborting.", 2, 11, ph->ver_major, ph->ver_minor);
+		return FALSE;
+	}
+	if (ph->config_size != LDM_DB_SIZE) {	/* 1 MiB in sectors. */
+		/* Warn the user and continue, carefully */
+		ldm_info ("Database is normally %u bytes, it claims to "
+			"be %llu bytes.", LDM_DB_SIZE,
+			(unsigned long long)ph->config_size );
+	}
+	if ((ph->logical_disk_size == 0) ||
+	    (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) {
+		ldm_error ("PRIVHEAD disk size doesn't match real disk size");
+		return FALSE;
+	}
+
+	if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) {
+		ldm_error ("PRIVHEAD contains an invalid GUID.");
+		return FALSE;
 	}
-	if (err != -1)
-		ldm_debug("Parsed VBLK successfully.\n");
-	return err;
+
+	ldm_debug ("Parsed PRIVHEAD successfully.");
+	return TRUE;
 }
 
 /**
- * add_partition_to_list - insert partition into a partition list
- * @pl:		sorted list of partitions
- * @hd:		gendisk structure to which the data partition belongs
- * @disk_minor:	minor number of the disk device
- * @start:	first sector within the disk device
- * @size:	number of sectors on the partition device
+ * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
+ * @data:  Raw database TOCBLOCK structure loaded from the device
+ * @toc:   In-memory toc structure in which to return parsed information
  *
- * This sanity checks the partition specified by @start and @size against the
- * device specified by @hd and inserts the partition into the sorted partition
- * list @pl if the checks pass.
+ * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
+ * in @data and sets up the in-memory tocblock structure @toc with the obtained
+ * information.
  *
- * On success return 1, otherwise return -1.
+ * N.B.  The *_start and *_size values returned in @toc are not range-checked.
  *
- * TODO: Add sanity check for overlapping partitions. (AIA)
- */ 
-static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd,
-		const int disk_minor, const unsigned long start,
-		const unsigned long size)
+ * Return:  TRUE   @toc contains the TOCBLOCK data
+ *          FALSE  @toc contents are undefined
+ */
+static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
 {
-	struct ldm_part *lp, *lptmp;
-	struct list_head *tmp;
+	BUG_ON (!data);
+	BUG_ON (!toc);
 
-	if (!hd->part)
-		return -1;
-	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
-		printk(LDM_CRIT "LDM partition exceeds physical disk. "
-				"Skipping.\n");
-		return -1;
+	if (MAGIC_TOCBLOCK != BE64 (data)) {
+		ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
+		return FALSE;
+	}
+	strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
+	toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
+	toc->bitmap1_start = BE64 (data + 0x2E);
+	toc->bitmap1_size  = BE64 (data + 0x36);
+
+	if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
+			sizeof (toc->bitmap1_name)) != 0) {
+		ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
+				TOC_BITMAP1, toc->bitmap1_name);
+		return FALSE;
+	}
+	strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
+	toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
+	toc->bitmap2_start = BE64 (data + 0x50);
+	toc->bitmap2_size  = BE64 (data + 0x58);
+	if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
+			sizeof (toc->bitmap2_name)) != 0) {
+		ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
+				TOC_BITMAP2, toc->bitmap2_name);
+		return FALSE;
 	}
-	lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL);
-	if (!lp) {
-		printk(LDM_CRIT "Not enough memory! Aborting LDM partition "
-				"parsing.\n");
-		return -2;
-	}
-	INIT_LIST_HEAD(&lp->part_list);
-	lp->start = start;
-	lp->size = size;
-	list_for_each(tmp, pl) {
-		lptmp = list_entry(tmp, struct ldm_part, part_list);
-		if (start > lptmp->start)
-			continue;
-		if (start < lptmp->start)
-			break;
-		printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n");
-		kfree(lp);
-		return -1;
-	}
-	list_add_tail(&lp->part_list, tmp);
-	ldm_debug("Added LDM partition successfully.\n");
-	return 1;
+	ldm_debug ("Parsed TOCBLOCK successfully.");
+	return TRUE;
 }
 
 /**
- * create_data_partitions - create the data partition devices
- * @hd:			gendisk structure in which to create the data partitions
- * @first_sector:	first sector within the disk device
- * @first_part_minor:	first minor number of data partition devices
- * @dev:		partition device holding the LDM database
- * @vm:			in memory vmdb structure of @dev
- * @ph:			in memory privhead structure of the disk device
- * @dk:			in memory ldmdisk structure of the disk device
+ * ldm_parse_vmdb - Read the LDM Database VMDB structure
+ * @data:  Raw database VMDB structure loaded from the device
+ * @vm:    In-memory vmdb structure in which to return parsed information
  *
- * The database contains ALL the partitions for ALL the disks, so we need to
- * filter out this specific disk. Using the disk's object id, we can find all
- * the partitions in the database that belong to this disk.
+ * This parses the LDM Database VMDB structure supplied in @data and sets up
+ * the in-memory vmdb structure @vm with the obtained information.
+ *
+ * N.B.  The *_start, *_size and *_seq values will be range-checked later.
  *
- * For each found partition, we create a corresponding partition device starting
- * with minor number @first_part_minor. But we do this in such a way that we
- * actually sort the partitions in order of on-disk position. Any invalid
- * partitions are completely ignored/skipped (an error is output but that's
- * all).
- *
- * Return 1 on success and -1 on error.
- */
-static int create_data_partitions(struct gendisk *hd,
-		const unsigned long first_sector, int first_part_minor,
-		struct block_device *bdev, const struct vmdb *vm,
-		const struct privhead *ph, const struct ldmdisk *dk,
-		unsigned long base)
+ * Return:  TRUE   @vm contains VMDB info
+ *          FALSE  @vm contents are undefined
+ */
+static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
 {
-	Sector sect;
-	unsigned char *data;
-	struct vblk *vb;
-	LIST_HEAD(pl);		/* Sorted list of partitions. */
-	struct ldm_part *lp;
-	struct list_head *tmp;
-	int vblk;
-	int vsize;		/* VBLK size. */
-	int perbuf;		/* VBLKs per buffer. */
-	int buffer, lastbuf, lastofs, err, disk_minor;
-
-	vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
-	if (!vb)
-		goto no_mem;
-	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > 512)
-		goto err_out;
-	perbuf  = 512 / vsize;
-	if (perbuf < 1 || 512 % vsize)
-		goto err_out;
-					/* 512 == VMDB size */
-	lastbuf = vm->last_vblk_seq / perbuf - 1;
-	lastofs = vm->last_vblk_seq % perbuf;
-	if (lastofs)
-		lastbuf++;
-	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
-			ph->config_size * 512)
-		goto err_out;
-	/*
-	 * Get the minor number of the parent device so we can check we don't
-	 * go beyond the end of the device.
-	 */
-	disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift;
-	for (buffer = 0; buffer < lastbuf; buffer++) {
-		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
-		if (!data)
-			goto read_err;
-		for (vblk = 0; vblk < perbuf; vblk++) {
-			u8 *block;
-			
-			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
-				break;
-			block = data + vsize * vblk;
-			if (block + vsize > data + 512)
-				goto brelse_out;
-			if (parse_vblk(block, vsize, vb) != 1)
-				continue;
-			if (vb->vblk_type != VBLK_PART)
-				continue;
-			if (dk->obj_id != vb->disk_id)
-				continue;
-			/* Ignore invalid partition errors. */
-			if (add_partition_to_list(&pl, hd, disk_minor,
-					first_sector + vb->start_sector +
-					ph->logical_disk_start,
-					vb->num_sectors) < -1)
-				goto brelse_out;
-		}
-		put_dev_sector(sect);
+	BUG_ON (!data);
+	BUG_ON (!vm);
+
+	if (MAGIC_VMDB != BE32 (data)) {
+		ldm_crit ("Cannot find the VMDB, database may be corrupt.");
+		return FALSE;
 	}
-	err = 1;
-out:
-	/* Finally create the nicely sorted data partitions. */
-	printk(" <");
-	list_for_each(tmp, &pl) {
-		lp = list_entry(tmp, struct ldm_part, part_list);
-		add_gd_partition(hd, first_part_minor++, lp->start, lp->size);
-	}
-	printk(" >\n");
-	if (!list_empty(&pl)) {
-		struct list_head *tmp2;
-
-		/* Cleanup the partition list which is now superfluous. */
-		list_for_each_safe(tmp, tmp2, &pl) {
-			lp = list_entry(tmp, struct ldm_part, part_list);
-			list_del(tmp);
-			kfree(lp);
-		}
+
+	vm->ver_major = BE16 (data + 0x12);
+	vm->ver_minor = BE16 (data + 0x14);
+	if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+		ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
+			"Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
+		return FALSE;
 	}
-	kfree(vb);
-	return err;
-brelse_out:
-	put_dev_sector(sect);
-	goto err_out;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	goto err_out;
-read_err:
-	printk(LDM_CRIT "Disk read failed in create_partitions.\n");
-err_out:
-	err = -1;
-	goto out;
+
+	vm->vblk_size     = BE32 (data + 0x08);
+	vm->vblk_offset   = BE32 (data + 0x0C);
+	vm->last_vblk_seq = BE32 (data + 0x04);
+
+	ldm_debug ("Parsed VMDB successfully.");
+	return TRUE;
 }
 
 /**
- * get_vnum - convert a variable-width, big endian number, to cpu u64 one
- * @block:	pointer to the variable-width number to convert
- * @err:	address of an integer into which to return the error code.
- *
- * This converts a variable-width, big endian number into a 64-bit, CPU format
- * number and returns the result with err set to 0. If an error occurs return 0
- * with err set to -1.
+ * ldm_compare_privheads - Compare two privhead objects
+ * @ph1:  First privhead
+ * @ph2:  Second privhead
  *
- * The first byte of a variable-width number is the size of the number in bytes.
+ * This compares the two privhead structures @ph1 and @ph2.
+ *
+ * Return:  TRUE   Identical
+ *          FALSE  Different
  */
-static u64 get_vnum(const u8 *block, int *err)
+static BOOL ldm_compare_privheads (const struct privhead *ph1,
+				   const struct privhead *ph2)
 {
-	u64 tmp = 0ULL;
-	u8 length = *block++;
+	BUG_ON (!ph1);
+	BUG_ON (!ph2);
 
-	if (length && length <= 8) {
-		while (length--)
-			tmp = (tmp << 8) | *block++;
-		*err = 0;
-	} else {
-		printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
-		*err = 1;
-	}
-	return tmp;
+	return ((ph1->ver_major          == ph2->ver_major)		&&
+		(ph1->ver_minor          == ph2->ver_minor)		&&
+		(ph1->logical_disk_start == ph2->logical_disk_start)	&&
+		(ph1->logical_disk_size  == ph2->logical_disk_size)	&&
+		(ph1->config_start       == ph2->config_start)		&&
+		(ph1->config_size        == ph2->config_size)		&&
+		!memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
 }
 
 /**
- * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
- * @block:	string to convert
- * @buffer:	output buffer
- * @buflen:	size of output buffer
+ * ldm_compare_tocblocks - Compare two tocblock objects
+ * @toc1:  First toc
+ * @toc2:  Second toc
  *
- * This converts @block, a counted, non-null-terminated ASCII string, into a
- * C-style, null-terminated, ASCII string and returns this in @buffer. The
- * maximum number of characters converted is given by @buflen.
+ * This compares the two tocblock structures @toc1 and @toc2.
  *
- * The first bytes of a counted string stores the length of the string in bytes.
+ * Return:  TRUE   Identical
+ *          FALSE  Different
+ */
+static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
+				   const struct tocblock *toc2)
+{
+	BUG_ON (!toc1);
+	BUG_ON (!toc2);
+
+	return ((toc1->bitmap1_start == toc2->bitmap1_start)	&&
+		(toc1->bitmap1_size  == toc2->bitmap1_size)	&&
+		(toc1->bitmap2_start == toc2->bitmap2_start)	&&
+		(toc1->bitmap2_size  == toc2->bitmap2_size)	&&
+		!strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
+			sizeof (toc1->bitmap1_name))		&&
+		!strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
+			sizeof (toc1->bitmap2_name)));
+}
+
+/**
+ * ldm_validate_privheads - Compare the primary privhead with its backups
+ * @bdev:  Device holding the LDM Database
+ * @ph1:   Memory struct to fill with ph contents
+ *
+ * Read and compare all three privheads from disk.
  *
- * Return the number of characters written to @buffer, not including the
- * terminating null character, on success, and -1 on error, in which case
- * @buffer is not defined.
+ * The privheads on disk show the size and location of the main disk area and
+ * the configuration area (the database).
+ *
+ * Return:  TRUE   Success
+ *          FALSE  Error
  */
-static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
+static BOOL ldm_validate_privheads (struct block_device *bdev,
+	unsigned long first_sector, struct privhead *ph1, struct gendisk *hd,
+	unsigned long first_minor)
 {
-	int length = block[0];
+	static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
+	struct privhead *ph[3] = { ph1 };
+	Sector sect;
+	u8 *data;
+	BOOL result = FALSE;
+	long num_sects;
+	int i;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ph1);
+
+	ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
+	ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
+	if (!ph[1] || !ph[2]) {
+		ldm_crit ("Out of memory.");
+		goto out;
+	}
 
-	if (length < 1)
-		return -1;
-	if (length >= buflen) {
-		printk(LDM_ERR "String too long for buffer in get_vstr(): "
-				"(%d/%d). Truncating.\n", length, buflen);
-		length = buflen - 1;
+	/* off[1 & 2] are relative to ph[0]->config_start */
+	ph[0]->config_start = 0;
+
+	/* Read and parse privheads */
+	for (i = 0; i < 3; i++) {
+		data = read_dev_sector (bdev,
+			first_sector + ph[0]->config_start + off[i], &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
+		}
+		result = ldm_parse_privhead (data, ph[i]);
+		put_dev_sector (sect);
+		if (!result) {
+			ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */
+			if (i < 2)
+				goto out;	/* Already logged */
+			else
+				break;	/* FIXME ignore for now, 3rd PH can fail on odd-sized disks */
+		}
 	}
-	memcpy(buffer, block + 1, length);
-	buffer[length] = (u8)'\0';
-	return length;
+
+	num_sects = hd->part[(first_minor >> hd->minor_shift)
+				<< hd->minor_shift].nr_sects;
+
+	if ((ph[0]->config_start > num_sects) ||
+	   ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
+		ldm_crit ("Database extends beyond the end of the disk.");
+		goto out;
+	}
+
+	if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
+	   ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
+		    > ph[0]->config_start)) {
+		ldm_crit ("Disk and database overlap.");
+		goto out;
+	}
+
+	if (!ldm_compare_privheads (ph[0], ph[1])) {
+		ldm_crit ("Primary and backup PRIVHEADs don't match.");
+		goto out;
+	}
+	/* FIXME ignore this for now
+	if (!ldm_compare_privheads (ph[0], ph[2])) {
+		ldm_crit ("Primary and backup PRIVHEADs don't match.");
+		goto out;
+	}*/
+	ldm_debug ("Validated PRIVHEADs successfully.");
+	result = TRUE;
+out:
+	kfree (ph[1]);
+	kfree (ph[2]);
+	return result;
 }
 
 /**
- * get_disk_objid - obtain the object id for the device we are working on
- * @dev:	partition device holding the LDM database
- * @vm:		in memory vmdb structure of the LDM database
- * @ph:		in memory privhead structure of the device we are working on
- * @dk:		in memory ldmdisk structure to return information into
- *
- * This obtains the object id for the device we are working on as defined by
- * the private header @ph. The obtained object id, together with the disk's
- * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
- *
- * A Disk has two Ids. The main one is a GUID in string format. The second,
- * used internally for cross-referencing, is a small, sequentially allocated,
- * number. The PRIVHEAD, just after the partition table, tells us the disk's
- * GUID. To find the disk's object id, we have to look through the database.
- *
- * Return 1 on success and -1 on error, in which case @dk is undefined.
- */
-static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm,
-		const struct privhead *ph, struct ldmdisk *dk,
-		unsigned long base)
+ * ldm_validate_tocblocks - Validate the table of contents and its backups
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
+ *
+ * Find and compare the four tables of contents of the LDM Database stored on
+ * @bdev and return the parsed information into @toc1.
+ *
+ * The offsets and sizes of the configs are range-checked against a privhead.
+ *
+ * Return:  TRUE   @toc1 contains validated TOCBLOCK info
+ *          FALSE  @toc1 contents are undefined
+ */
+static BOOL ldm_validate_tocblocks (struct block_device *bdev,
+	unsigned long base, struct ldmdb *ldb)
 {
+	static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
+	struct tocblock *tb[4];
+	struct privhead *ph;
 	Sector sect;
-	unsigned char *data;
-	u8 *disk_id;
-	int vblk;
-	int vsize;		/* VBLK size. */
-	int perbuf;		/* VBLKs per buffer. */
-	int buffer, lastbuf, lastofs, err;
-
-	disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
-	if (!disk_id)
-		goto no_mem;
-	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > 512)
-		goto err_out;
-	perbuf  = 512 / vsize;
-	if (perbuf < 1 || 512 % vsize)
-		goto err_out;
-					/* 512 == VMDB size */
-	lastbuf = vm->last_vblk_seq / perbuf - 1;
-	lastofs = vm->last_vblk_seq % perbuf;
-	if (lastofs)
-		lastbuf++;
-	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
-			ph->config_size * 512)
-		goto err_out;
-	for (buffer = 0; buffer < lastbuf; buffer++) {
-		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
-		if (!data)
-			goto read_err;
-		for (vblk = 0; vblk < perbuf; vblk++) {
-			int rel_objid, rel_name, delta;
-			u8 *block;
-
-			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
-				break;
-			block = data + vblk * vsize;
-			delta = vblk * vsize + 0x18;
-			if (delta >= 512)
-				goto brelse_out;
-			if (block[0x0D] != 0)	/* Extended VBLK, ignore */
-				continue;
-			if ((block[0x13] != VBLK_DSK1) &&
-			    (block[0x13] != VBLK_DSK2))
-				continue;
-			/* Calculate relative offsets. */
-			rel_objid = 1 + block[0x18];
-			if (delta + rel_objid >= 512)
-				goto brelse_out;
-			rel_name  = 1 + block[0x18 + rel_objid] + rel_objid;
-			if (delta + rel_name >= 512 ||
-			    delta + rel_name + block[0x18 + rel_name] >= 512)
-				goto brelse_out;
-			err = get_vstr(block + 0x18 + rel_name, disk_id,
-					DISK_ID_SIZE);
-			if (err == -1)
-				goto brelse_out;
-			if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
-				dk->obj_id = get_vnum(block + 0x18, &err);
-				put_dev_sector(sect);
-				if (err)
-					goto out;
-				strncpy(dk->disk_id, ph->disk_id,
-						sizeof(dk->disk_id));
-				dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
-				err = 1;
-				goto out;
-			}
+	u8 *data;
+	BOOL result = FALSE;
+	int i;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
+
+	ph    = &ldb->ph;
+	tb[0] = &ldb->toc;
+	tb[1] = kmalloc (sizeof (*tb[1]), GFP_KERNEL);
+	tb[2] = kmalloc (sizeof (*tb[2]), GFP_KERNEL);
+	tb[3] = kmalloc (sizeof (*tb[3]), GFP_KERNEL);
+	if (!tb[1] || !tb[2] || !tb[3]) {
+		ldm_crit ("Out of memory.");
+		goto out;
+	}
+
+	for (i = 0; i < 4; i++)		/* Read and parse all four toc's. */
+	{
+		data = read_dev_sector (bdev, base + off[i], &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
 		}
-		put_dev_sector(sect);
+		result = ldm_parse_tocblock (data, tb[i]);
+		put_dev_sector (sect);
+		if (!result)
+			goto out;	/* Already logged */
+	}
+
+	/* Range check the toc against a privhead. */
+	if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
+	    ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > ph->config_size)) {
+		ldm_crit ("The bitmaps are out of range.  Giving up.");
+		goto out;
+	}
+
+	if (!ldm_compare_tocblocks (tb[0], tb[1]) ||	/* Compare all tocs. */
+	    !ldm_compare_tocblocks (tb[0], tb[2]) ||
+	    !ldm_compare_tocblocks (tb[0], tb[3])) {
+		ldm_crit ("The TOCBLOCKs don't match.");
+		goto out;
 	}
-	err = -1;
+
+	ldm_debug ("Validated TOCBLOCKs successfully.");
+	result = TRUE;
 out:
-	kfree(disk_id);
-	return err;
-brelse_out:
-	put_dev_sector(sect);
-	goto err_out;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	goto err_out;
-read_err:
-	printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
-err_out:
-	err = -1;
-	goto out;
+	kfree (tb[1]);
+	kfree (tb[2]);
+	kfree (tb[3]);
+	return result;
 }
 
 /**
- * parse_vmdb - parse the LDM database vmdb structure
- * @buffer:	LDM database vmdb structure loaded from the device
- * @vm:		in memory vmdb structure to return parsed information in
- *
- * This parses the LDM database vmdb structure supplied in @buffer and sets up
- * the in memory vmdb structure @vm with the obtained information.
- *
- * Return 1 on success and -1 on error, in which case @vm is undefined.
+ * ldm_validate_vmdb - Read the VMDB and validate it
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
+ *
+ * Find the vmdb of the LDM Database stored on @bdev and return the parsed
+ * information in @ldb.
  *
- * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
- * checked for validity, so make sure to check them when using them.
+ * Return:  TRUE   @ldb contains validated VBDB info
+ *          FALSE  @ldb contents are undefined
  */
-static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
+static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
+			       struct ldmdb *ldb)
 {
-	if (MAGIC_VMDB != BE32(buffer)) {
-		printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
-		return -1;
+	Sector sect;
+	u8 *data;
+	BOOL result = FALSE;
+	struct vmdb *vm;
+	struct tocblock *toc;
+
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
+
+	vm  = &ldb->vm;
+	toc = &ldb->toc;
+
+	data = read_dev_sector (bdev, base + OFF_VMDB, &sect);
+	if (!data) {
+		ldm_crit ("Disk read failed.");
+		return FALSE;
 	}
-	vm->ver_major = BE16(buffer + 0x12);
-	vm->ver_minor = BE16(buffer + 0x14);
-	if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
-		printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
-				"Aborting.\n", 4, 10, vm->ver_major,
-				vm->ver_minor);
-		return -1;
+
+	if (!ldm_parse_vmdb (data, vm))
+		goto out;				/* Already logged */
+
+	/* Are there uncommitted transactions? */
+	if (BE16(data + 0x10) != 0x01) {
+		ldm_crit ("Database is not in a consistant state.  Aborting.");
+		goto out;
 	}
-	vm->vblk_size	  = BE32(buffer + 0x08);
-	vm->vblk_offset   = BE32(buffer + 0x0C);
-	vm->last_vblk_seq = BE32(buffer + 0x04);
 
-	ldm_debug("Parsed VMDB successfully.\n");
-	return 1;
+	if (vm->vblk_offset != 512)
+		ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
+
+	/* FIXME: How should we handle this situation? */
+	if ((vm->vblk_size * vm->last_vblk_seq) != (toc->bitmap1_size << 9))
+		ldm_info ("VMDB and TOCBLOCK don't agree on the database size.");
+
+	result = TRUE;
+out:
+	put_dev_sector (sect);
+	return result;
 }
 
+
 /**
- * validate_vmdb - validate the vmdb
- * @dev:	partition device holding the LDM database
- * @vm:		in memory vmdb in which to return information
+ * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
+ * @bdev:  Device holding the LDM Database
  *
- * Find the vmdb of the LDM database stored on @dev and return the parsed
- * information into @vm.
+ * This function provides a weak test to decide whether the device is a dynamic
+ * disk or not.  It looks for an MS-DOS-style partition table containing at
+ * least one partition of type 0x42 (formerly SFS, now used by Windows for
+ * dynamic disks).
+ *
+ * N.B.  The only possible error can come from the read_dev_sector and that is
+ *       only likely to happen if the underlying device is strange.  If that IS
+ *       the case we should return zero to let someone else try.
  *
- * Return 1 on success and -1 on error, in which case @vm is undefined.
+ * Return:  TRUE   @bdev is a dynamic disk
+ *          FALSE  @bdev is not a dynamic disk, or an error occurred
  */
-static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base)
+static BOOL ldm_validate_partition_table (struct block_device *bdev)
 {
 	Sector sect;
-	unsigned char *data;
-	int ret;
+	u8 *data;
+	struct partition *p;
+	int i;
+	BOOL result = FALSE;
 
-	data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, &sect);
+	BUG_ON (!bdev);
+
+	data = read_dev_sector (bdev, 0, &sect);
 	if (!data) {
-		printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
-		return -1;
+		ldm_crit ("Disk read failed.");
+		return FALSE;
+	}
+
+	if (*(u16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC)) {
+		ldm_debug ("No MS-DOS partition table found.");
+		goto out;
 	}
-	ret = parse_vmdb(data, vm);
-	put_dev_sector(sect);
-	return ret;
+
+	p = (struct partition*)(data + 0x01BE);
+	for (i = 0; i < 4; i++, p++)
+		if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) {
+			result = TRUE;
+			break;
+		}
+
+	if (result)
+		ldm_debug ("Parsed partition table successfully.");
+	else
+		ldm_debug ("Found an MS-DOS partition table, not a dynamic disk.");
+out:
+	put_dev_sector (sect);
+	return result;
 }
 
 /**
- * compare_tocblocks - compare two tables of contents
- * @toc1:	first toc
- * @toc2:	second toc
+ * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
+ * @ldb:  Cache of the database structures
  *
- * This compares the two tables of contents @toc1 and @toc2.
+ * The LDM Database contains a list of all partitions on all dynamic disks.  The
+ * primary PRIVHEAD, at the beginning of the physical disk, tells us the GUID of
+ * this disk.  This function searches for the GUID in a linked list of vblk's.
  *
- * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
+ * Return:  Pointer, A matching vblk was found
+ *          NULL,    No match, or an error
  */
-static int compare_tocblocks(const struct tocblock *toc1,
-		const struct tocblock *toc2)
+static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
 {
-	if ((toc1->bitmap1_start == toc2->bitmap1_start)	&&
-	    (toc1->bitmap1_size  == toc2->bitmap1_size)		&&
-	    (toc1->bitmap2_start == toc2->bitmap2_start)	&&
-	    (toc1->bitmap2_size  == toc2->bitmap2_size)		&&
-	    !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
-			sizeof(toc1->bitmap1_name))		&&
-	    !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
-			sizeof(toc1->bitmap2_name)))
-		return 1;
-	return -1;
+	struct list_head *item;
+
+	BUG_ON (!ldb);
+
+	list_for_each (item, &ldb->v_disk) {
+		struct vblk *v = list_entry (item, struct vblk, list);
+		if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
+			return v;
+	}
+
+	return NULL;
 }
 
 /**
- * parse_tocblock - parse the LDM database table of contents structure
- * @buffer:	LDM database toc structure loaded from the device
- * @toc:	in memory toc structure to return parsed information in
+ * ldm_create_partition - Create a kernel partition device
+ * @hd:     gendisk structure in which to create partition
+ * @minor:  Create a this minor number on the device
+ * @start:  Offset (in sectors) into the device of the partition
+ * @size:   Size (in sectors) of the partition
  *
- * This parses the LDM database table of contents structure supplied in @buffer
- * and sets up the in memory table of contents structure @toc with the obtained
- * information.
+ * This validates the range, then puts an entry into the kernel's partition
+ * table.
+ *
+ * Return:  TRUE   Created the partition
+ *          FALSE  Error
+ */
+static BOOL ldm_create_partition (struct gendisk *hd, int minor, int start,
+				  int size)
+{
+	int disk_minor;
+
+	BUG_ON (!hd);;
+	BUG_ON (!hd->part);
+
+	/* Get the minor number of the parent device
+	 * so we can check we don't go beyond the end of the device.  */
+	disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
+	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+		ldm_crit ("Partition exceeds physical disk. Aborting.");
+		return FALSE;
+	}
+	add_gd_partition (hd, minor, start, size);
+	ldm_debug ("Created partition successfully.");
+	return TRUE;
+}
+
+/**
+ * ldm_create_data_partitions - Create data partitions for this device
+ * @pp:   List of the partitions parsed so far
+ * @ldb:  Cache of the database structures
  *
- * Return 1 on success and -1 on error, in which case @toc is undefined.
+ * The database contains ALL the partitions for ALL disk groups, so we need to
+ * filter out this specific disk. Using the disk's object id, we can find all
+ * the partitions in the database that belong to this disk.
+ *
+ * Add each partition in our database, to the parsed_partitions structure.
+ *
+ * N.B.  This function creates the partitions in the order it finds partition
+ *       objects in the linked list.
  *
- * FIXME: The *_start and *_size values returned in @toc are not been checked
- * for validity but as we don't use the actual values for anything other than
- * comparing between the toc and its backups, the values are not important.
+ * Return:  TRUE   Partition created
+ *          FALSE  Error, probably a range checking problem
  */
-static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
+static BOOL ldm_create_data_partitions (struct gendisk *hd,
+	unsigned long first_sector, int first_minor, const struct ldmdb *ldb)
 {
-	if (MAGIC_TOCBLOCK != BE64(buffer)) {
-		printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
-				"corrupt.\n");
-		return -1;
+	struct list_head *item;
+	struct vblk_part *part;
+	struct vblk *disk;
+	int disk_minor;
+	int minor;
+
+	BUG_ON (!hd);
+	BUG_ON (!ldb);
+
+	disk = ldm_get_disk_objid (ldb);
+	if (!disk) {
+		ldm_crit ("Can't find the ID of this disk in the database.");
+		return FALSE;
 	}
-	strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
-	toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
-	toc->bitmap1_start = BE64(buffer + 0x2E);
-	toc->bitmap1_size  = BE64(buffer + 0x36);
-	/*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
-	if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
-			sizeof(toc->bitmap1_name)) != 0) {
-		printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
-				"%s.\n", TOC_BITMAP1, toc->bitmap1_name);
-		return -1;
+
+	/* We use the range-check the partitions against the parent device. */
+	disk_minor = (first_minor >> hd->minor_shift) << hd->minor_shift;
+	minor = first_minor;
+
+	printk (" [LDM]");
+
+	/* Create the data partitions */
+	list_for_each (item, &ldb->v_part) {
+		struct vblk *vb;
+		vb = list_entry (item, struct vblk, list);
+		part = &vb->vblk.part;
+
+		if (part->disk_id != disk->obj_id)
+			continue;
+
+		if (!ldm_create_partition (hd, minor,
+		    part->start + ldb->ph.logical_disk_start, part->size))
+			continue;			/* Already logged */
+		minor++;
 	}
-	strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
-	toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
-	toc->bitmap2_start = BE64(buffer + 0x50);
-	toc->bitmap2_size  = BE64(buffer + 0x58);
-	/*toc->bitmap2_flags = BE64(buffer + 0x60);*/
-	if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
-			sizeof(toc->bitmap2_name)) != 0) {
-		printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
-				"%s.\n", TOC_BITMAP2, toc->bitmap2_name);
+
+	printk ("\n");
+	return TRUE;
+}
+
+
+/**
+ * ldm_relative - Calculate the next relative offset
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @base:    Size of the previous fixed width fields
+ * @offset:  Cumulative size of the previous variable-width fields
+ *
+ * Because many of the VBLK fields are variable-width, it's necessary
+ * to calculate each offset based on the previous one and the length
+ * of the field it pointed to.
+ *
+ * Return:  -1 Error, the calculated offset exceeded the size of the buffer
+ *           n OK, a range-checked offset into buffer
+ */
+static int ldm_relative (const u8 *buffer, int buflen, int base, int offset)
+{
+
+	base += offset;
+	if ((!buffer) || (offset < 0) || (base > buflen))
 		return -1;
-	}
-	ldm_debug("Parsed TOCBLOCK successfully.\n");
-	return 1;
+	if ((base + buffer[base]) >= buflen)
+		return -1;
+
+	return buffer[base] + offset + 1;
 }
 
 /**
- * validate_tocblocks - validate the table of contents and its backups
- * @dev:	partition device holding the LDM database
- * @toc1:	in memory table of contents in which to return information
+ * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
+ * @block:  Pointer to the variable-width number to convert
+ *
+ * Large numbers in the LDM Database are often stored in a packed format.  Each
+ * number is prefixed by a one byte width marker.  All numbers in the database
+ * are stored in big-endian byte order.  This function reads one of these
+ * numbers and returns the result
  *
- * Find and compare the four tables of contents of the LDM database stored on
- * @dev and return the parsed information into @toc1.
+ * N.B.  This function DOES NOT perform any range checking, though the most
+ *       it will read is eight bytes.
  *
- * Return 1 on success and -1 on error, in which case @toc1 is undefined.
+ * Return:  n A number
+ *          0 Zero, or an error occurred
  */
-static int validate_tocblocks(struct block_device *bdev,
-			struct tocblock *toc1,
-			unsigned long base)
+static u64 ldm_get_vnum (const u8 *block)
 {
-	Sector sect;
-	unsigned char *data;
-	struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
-	int err;
-
-	toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
-	if (!toc2)
-		goto no_mem;
-	toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
-	if (!toc3)
-		goto no_mem;
-	toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
-	if (!toc4)
-		goto no_mem;
-	/* Read and parse first toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc1);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse second toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc2);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse third toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc3);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Read and parse fourth toc. */
-	data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
-		goto err_out;
-	}
-	err = parse_tocblock(data, toc4);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	/* Compare all tocs. */
-	err = compare_tocblocks(toc1, toc2);
-	if (err != 1) {
-		printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
-		goto out;
-	}
-	err = compare_tocblocks(toc3, toc4);
-	if (err != 1) {
-		printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
-		goto out;
-	}
-	err = compare_tocblocks(toc1, toc3);
-	if (err != 1)
-		printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
+	u64 tmp = 0;
+	u8 length;
+
+	BUG_ON (!block);
+
+	length = *block++;
+
+	if (length && length <= 8)
+		while (length--)
+			tmp = (tmp << 8) | *block++;
 	else
-		ldm_debug("Validated TOCBLOCKs successfully.\n");
-out:
-	kfree(toc2);
-	kfree(toc3);
-	kfree(toc4);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-err_out:
-	err = -1;
-	goto out;
+		ldm_error ("Illegal length %d.", length);
+
+	return tmp;
 }
 
 /**
- * compare_privheads - compare two privheads
- * @ph1:	first privhead
- * @ph2:	second privhead
- *
- * This compares the two privheads @ph1 and @ph2.
- *
- * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
- */
-static int compare_privheads(const struct privhead *ph1,
-		const struct privhead *ph2)
-{
-	if ((ph1->ver_major == ph2->ver_major)			 &&
-	    (ph1->ver_minor == ph2->ver_minor)			 &&
-	    (ph1->logical_disk_start == ph2->logical_disk_start) &&
-	    (ph1->logical_disk_size  == ph2->logical_disk_size)	 &&
-	    (ph1->config_start == ph2->config_start)		 &&
-	    (ph1->config_size  == ph2->config_size)		 &&
-	    !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
-		return 1;
-	return -1;
+ * ldm_get_vstr - Read a length-prefixed string into a buffer
+ * @block:   Pointer to the length marker
+ * @buffer:  Location to copy string to
+ * @buflen:  Size of the output buffer
+ *
+ * Many of the strings in the LDM Database are not NULL terminated.  Instead
+ * they are prefixed by a one byte length marker.  This function copies one of
+ * these strings into a buffer.
+ *
+ * N.B.  This function DOES NOT perform any range checking on the input.
+ *       If the buffer is too small, the output will be truncated.
+ *
+ * Return:  0, Error and @buffer contents are undefined
+ *          n, String length in characters (excluding NULL)
+ *          buflen-1, String was truncated.
+ */
+static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
+{
+	int length;
+
+	BUG_ON (!block);
+	BUG_ON (!buffer);
+
+	length = block[0];
+	if (length >= buflen) {
+		ldm_error ("Truncating string %d -> %d.", length, buflen);
+		length = buflen - 1;
+	}
+	memcpy (buffer, block + 1, length);
+	buffer[length] = 0;
+	return length;
+}
+
+
+/**
+ * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Component object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Component VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
+	struct vblk_comp *comp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_child  = ldm_relative (buffer, buflen, 0x1D, r_vstate);
+	r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
+
+	if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
+		r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
+		r_cols   = ldm_relative (buffer, buflen, 0x2E, r_stripe);
+		len = r_cols;
+	} else {
+		r_stripe = 0;
+		r_cols   = 0;
+		len = r_parent;
+	}
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_CMP3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	comp = &vb->vblk.comp;
+	ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
+		sizeof (comp->state));
+	comp->type      = buffer[0x18 + r_vstate];
+	comp->children  = ldm_get_vnum (buffer + 0x1D + r_vstate);
+	comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
+	comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk Group VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_diskid, r_id1, r_id2, len;
+	struct vblk_dgrp *dgrp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
+
+	if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
+		r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
+		r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
+		len = r_id2;
+	} else {
+		r_id1 = 0;
+		r_id2 = 0;
+		len = r_diskid;
+	}
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DGR3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	dgrp = &vb->vblk.dgrp;
+	ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
+		sizeof (dgrp->disk_id));
+	return TRUE;
 }
 
 /**
- * validate_privheads - compare the privhead backups to the first one
- * @dev:	partition device holding the LDM database
- * @ph1:	first privhead which we have already validated before
- *
- * We already have one privhead from the beginning of the disk.
- * Now we compare the two other copies for safety.
- *
- * Return 1 on succes and -1 on error.
- */
-static int validate_privheads(struct block_device *bdev,
-			      const struct privhead *ph1,
-			      unsigned long base)
+ * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk Group VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
 {
-	Sector sect;
-	unsigned char *data;
-	struct privhead *ph2 = NULL, *ph3 = NULL;
-	int err;
-
-	ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
-	if (!ph2)
-		goto no_mem;
-	ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
-	if (!ph3)
-		goto no_mem;
-	data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
-		goto err_out;
+	char buf[64];
+	int r_objid, r_name, r_id1, r_id2, len;
+	struct vblk_dgrp *dgrp;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+
+	if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
+		r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
+		r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
+		len = r_id2;
+	} else {
+		r_id1 = 0;
+		r_id2 = 0;
+		len = r_name;
 	}
-	err = parse_privhead(data, ph2);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, &sect);
-	if (!data) {
-		printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
-		goto err_out;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DGR4;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	dgrp = &vb->vblk.dgrp;
+
+	ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_diskid, r_altname, len;
+	struct vblk_disk *disk;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid   = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name    = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_diskid  = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
+	len = r_altname;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DSK3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	disk = &vb->vblk.disk;
+	ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
+		sizeof (disk->alt_name));
+	if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
+		return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Disk object (version 4) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Disk VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, len;
+	struct vblk_disk *disk;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name  = ldm_relative (buffer, buflen, 0x18, r_objid);
+	len     = r_name;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_DSK4;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	disk = &vb->vblk.disk;
+	memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
+	return TRUE;
+}
+
+/**
+ * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Partition object (version 3) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Partition VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
+	struct vblk_part *part;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_size   = ldm_relative (buffer, buflen, 0x34, r_name);
+	r_parent = ldm_relative (buffer, buflen, 0x34, r_size);
+	r_diskid = ldm_relative (buffer, buflen, 0x34, r_parent);
+
+	if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
+		r_index = ldm_relative (buffer, buflen, 0x34, r_diskid);
+		len = r_index;
+	} else {
+		r_index = 0;
+		len = r_diskid;
 	}
-	err = parse_privhead(data, ph3);
-	put_dev_sector(sect);
-	if (err != 1)
-		goto out;
-	err = compare_privheads(ph1, ph2);
-	if (err != 1) {
-		printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
-		goto out;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_PRT3;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	part = &vb->vblk.part;
+	part->start         = BE64         (buffer + 0x24 + r_name);
+	part->volume_offset = BE64         (buffer + 0x2C + r_name);
+	part->size          = ldm_get_vnum (buffer + 0x34 + r_name);
+	part->parent_id     = ldm_get_vnum (buffer + 0x34 + r_size);
+	part->disk_id       = ldm_get_vnum (buffer + 0x34 + r_parent);
+	if (vb->flags & VBLK_FLAG_PART_INDEX)
+		part->partnum = buffer[0x35 + r_diskid];
+	else
+		part->partnum = 0;
+
+	return TRUE;
+}
+
+/**
+ * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
+ * @buffer:  Block of data being worked on
+ * @buflen:  Size of the block of data
+ * @vb:      In-memory vblk in which to return information
+ *
+ * Read a raw VBLK Volume object (version 5) into a vblk structure.
+ *
+ * Return:  TRUE   @vb contains a Volume VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
+{
+	int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
+	int r_drive, len;
+	struct vblk_volu *volu;
+
+	BUG_ON (!buffer);
+	BUG_ON (!vb);
+
+	r_objid  = ldm_relative (buffer, buflen, 0x18, 0);
+	r_name   = ldm_relative (buffer, buflen, 0x18, r_objid);
+	r_vtype  = ldm_relative (buffer, buflen, 0x18, r_name);
+	r_child  = ldm_relative (buffer, buflen, 0x2E, r_vtype);
+	r_size   = ldm_relative (buffer, buflen, 0x3E, r_child);
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_ID1)
+		r_id1 = ldm_relative (buffer, buflen, 0x53, r_size);
+	else
+		r_id1 = r_size;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_ID2)
+		r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1);
+	else
+		r_id2 = r_id1;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE)
+		r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2);
+	else
+		r_size2 = r_id2;
+
+	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE)
+		r_drive = ldm_relative (buffer, buflen, 0x53, r_size2);
+	else
+		r_drive = r_size2;
+
+	len = r_drive;
+	if (len < 0)
+		return FALSE;
+
+	len += VBLK_SIZE_VOL5;
+	if (len != BE32 (buffer + 0x14))
+		return FALSE;
+
+	volu = &vb->vblk.volu;
+
+	ldm_get_vstr (buffer + 0x18 + r_name,  volu->volume_type,
+		sizeof (volu->volume_type));
+	memcpy (volu->volume_state, buffer + 0x19 + r_vtype,
+			sizeof (volu->volume_state));
+	volu->size = ldm_get_vnum (buffer + 0x3E + r_child);
+	volu->partition_type = buffer[0x42 + r_size];
+	memcpy (volu->guid, buffer + 0x43 + r_size,  sizeof (volu->guid));
+	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
+		ldm_get_vstr (buffer + 0x53 + r_size,  volu->drive_hint,
+			sizeof (volu->drive_hint));
 	}
-	err = compare_privheads(ph1, ph3);
-	if (err != 1)
-		printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
+	return TRUE;
+}
+
+/**
+ * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
+ * @buf:  Block of data being worked on
+ * @len:  Size of the block of data
+ * @vb:   In-memory vblk in which to return information
+ *
+ * Read a raw VBLK object into a vblk structure.  This function just reads the
+ * information common to all VBLK types, then delegates the rest of the work to
+ * helper functions: ldm_parse_*.
+ *
+ * Return:  TRUE   @vb contains a VBLK
+ *          FALSE  @vb contents are not defined
+ */
+static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
+{
+	BOOL result = FALSE;
+	int r_objid;
+
+	BUG_ON (!buf);
+	BUG_ON (!vb);
+
+	r_objid = ldm_relative (buf, len, 0x18, 0);
+	if (r_objid < 0) {
+		ldm_error ("VBLK header is corrupt.");
+		return FALSE;
+	}
+
+	vb->flags  = buf[0x12];
+	vb->type   = buf[0x13];
+	vb->obj_id = ldm_get_vnum (buf + 0x18);
+	ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
+
+	switch (vb->type) {
+		case VBLK_CMP3:  result = ldm_parse_cmp3 (buf, len, vb); break;
+		case VBLK_DSK3:  result = ldm_parse_dsk3 (buf, len, vb); break;
+		case VBLK_DSK4:  result = ldm_parse_dsk4 (buf, len, vb); break;
+		case VBLK_DGR3:  result = ldm_parse_dgr3 (buf, len, vb); break;
+		case VBLK_DGR4:  result = ldm_parse_dgr4 (buf, len, vb); break;
+		case VBLK_PRT3:  result = ldm_parse_prt3 (buf, len, vb); break;
+		case VBLK_VOL5:  result = ldm_parse_vol5 (buf, len, vb); break;
+	}
+
+	if (result)
+		ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
+			 (unsigned long long) vb->obj_id, vb->type);
 	else
-		/* We _could_ have checked more. */
-		ldm_debug("Validated PRIVHEADs successfully.\n");
-out:
-	kfree(ph2);
-	kfree(ph3);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-err_out:
-	err = -1;
-	goto out;
+		ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
+			(unsigned long long) vb->obj_id, vb->type);
+
+	return result;
 }
 
+
 /**
- * create_partition - validate input and create a kernel partition device
- * @hd:		gendisk structure in which to create partition
- * @minor:	minor number for device to create
- * @start:	starting offset of the partition into the parent device
- * @size:	size of the partition
+ * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
+ * @data:  Raw VBLK to add to the database
+ * @len:   Size of the raw VBLK
+ * @ldb:   Cache of the database structures
  *
- * This validates the range, then puts an entry into the kernel's partition
- * table.
+ * The VBLKs are sorted into categories.  Partitions are also sorted by offset.
  *
- * @start and @size are numbers of sectors.
+ * N.B.  This function does not check the validity of the VBLKs.
  *
- * Return 1 on succes and -1 on error.
+ * Return:  TRUE   The VBLK was added
+ *          FALSE  An error occurred
  */
-static int create_partition(struct gendisk *hd, const int minor,
-		const int start, const int size)
+static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
 {
-	int disk_minor;
+	struct vblk *vb;
+	struct list_head *item;
 
-	if (!hd->part)
-		return -1;
-	/*
-	 * Get the minor number of the parent device so we can check we don't
-	 * go beyond the end of the device.
-	 */
-	disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
-	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
-		printk(LDM_CRIT "LDM Partition exceeds physical disk. "
-				"Aborting.\n");
-		return -1;
+	BUG_ON (!data);
+	BUG_ON (!ldb);
+
+	vb = kmalloc (sizeof (*vb), GFP_KERNEL);
+	if (!vb) {
+		ldm_crit ("Out of memory.");
+		return FALSE;
+	}
+
+	if (!ldm_parse_vblk (data, len, vb))
+		return FALSE;			/* Already logged */
+
+	/* Put vblk into the correct list. */
+	switch (vb->type) {
+	case VBLK_DGR3:
+	case VBLK_DGR4:
+		list_add (&vb->list, &ldb->v_dgrp);
+		break;
+	case VBLK_DSK3:
+	case VBLK_DSK4:
+		list_add (&vb->list, &ldb->v_disk);
+		break;
+	case VBLK_VOL5:
+		list_add (&vb->list, &ldb->v_volu);
+		break;
+	case VBLK_CMP3:
+		list_add (&vb->list, &ldb->v_comp);
+		break;
+	case VBLK_PRT3:
+		/* Sort by the partition's start sector. */
+		list_for_each (item, &ldb->v_part) {
+			struct vblk *v = list_entry (item, struct vblk, list);
+			if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
+			    (v->vblk.part.start > vb->vblk.part.start)) {
+				list_add_tail (&vb->list, &v->list);
+				return TRUE;
+			}
+		}
+		list_add_tail (&vb->list, &ldb->v_part);
+		break;
 	}
-	add_gd_partition(hd, minor, start, size);
-	ldm_debug("Created partition successfully.\n");
-	return 1;
+	return TRUE;
 }
 
 /**
- * parse_privhead - parse the LDM database PRIVHEAD structure
- * @buffer:	LDM database privhead structure loaded from the device
- * @ph:		in memory privhead structure to return parsed information in
+ * ldm_frag_add - Add a VBLK fragment to a list
+ * @data:   Raw fragment to be added to the list
+ * @size:   Size of the raw fragment
+ * @frags:  Linked list of VBLK fragments
  *
- * This parses the LDM database PRIVHEAD structure supplied in @buffer and
- * sets up the in memory privhead structure @ph with the obtained information.
+ * Fragmented VBLKs may not be consecutive in the database, so they are placed
+ * in a list so they can be pieced together later.
  *
- * Return 1 on succes and -1 on error, in which case @ph is undefined.
+ * Return:  TRUE   Success, the VBLK was added to the list
+ *          FALSE  Error, a problem occurred
  */
-static int parse_privhead(const u8 *buffer, struct privhead *ph)
+static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
 {
-	if (MAGIC_PRIVHEAD != BE64(buffer)) {
-		printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
-				"is corrupt. Aborting.\n");
-		return -1;
+	struct frag *f;
+	struct list_head *item;
+	int rec, num, group;
+
+	BUG_ON (!data);
+	BUG_ON (!frags);
+
+	group = BE32 (data + 0x08);
+	rec   = BE16 (data + 0x0C);
+	num   = BE16 (data + 0x0E);
+	if ((num < 1) || (num > 4)) {
+		ldm_error ("A VBLK claims to have %d parts.", num);
+		return FALSE;
 	}
-	ph->ver_major = BE16(buffer + 0x000C);
-	ph->ver_minor = BE16(buffer + 0x000E);
-	if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
-		printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
-				"Aborting.\n", 2, 11, ph->ver_major,
-				ph->ver_minor);
-		return -1;
+
+	list_for_each (item, frags) {
+		f = list_entry (item, struct frag, list);
+		if (f->group == group)
+			goto found;
 	}
-	ph->config_start = BE64(buffer + 0x012B);
-	ph->config_size  = BE64(buffer + 0x0133);
-	if (ph->config_size != LDM_DB_SIZE) {	/* 1 MiB in sectors. */
-		printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
-				"bytes. Aborting.\n", LDM_DB_SIZE,
-				ph->config_size);
-		return -1;
+
+	f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
+	if (!f) {
+		ldm_crit ("Out of memory.");
+		return FALSE;
 	}
-	ph->logical_disk_start = BE64(buffer + 0x011B);
-	ph->logical_disk_size  = BE64(buffer + 0x0123);
-	if (!ph->logical_disk_size ||
-	    ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
-		return -1;
 
-	memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
+	f->group = group;
+	f->num   = num;
+	f->rec   = rec;
+	f->map   = 0xFF << num;
+
+	list_add_tail (&f->list, frags);
+found:
+	if (f->map & (1 << rec)) {
+		ldm_error ("Duplicate VBLK, part %d.", rec);
+		f->map &= 0x7F;			/* Mark the group as broken */
+		return FALSE;
+	}
 
-	ldm_debug("Parsed PRIVHEAD successfully.\n");
-	return 1;
+	f->map |= (1 << rec);
+
+	if (num > 0) {
+		data += VBLK_SIZE_HEAD;
+		size -= VBLK_SIZE_HEAD;
+	}
+	memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
+
+	return TRUE;
 }
 
 /**
- * create_db_partition - create a dedicated partition for our database
- * @hd:		gendisk structure in which to create partition
- * @dev:	device of which to create partition
- * @ph:		@dev's LDM database private header
+ * ldm_frag_free - Free a linked list of VBLK fragments
+ * @list:  Linked list of fragments
  *
- * Find the primary private header, locate the LDM database, then create a
- * partition to wrap it.
+ * Free a linked list of VBLK fragments
  *
- * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
+ * Return:  none
  */
-static int create_db_partition(struct gendisk *hd, struct block_device *bdev,
-		const unsigned long first_sector, const int first_part_minor,
-		struct privhead *ph)
+static void ldm_frag_free (struct list_head *list)
 {
-	Sector sect;
-	unsigned char *data;
-	int err;
+	struct list_head *item, *tmp;
 
-	data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, &sect);
-	if (!data) {
-		printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
-		return -1;
-	}
-	if (BE64(data) != MAGIC_PRIVHEAD) {
-		ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
-				"or corrupt LDM database.\n");
-		return 0;
+	BUG_ON (!list);
+
+	list_for_each_safe (item, tmp, list)
+		kfree (list_entry (item, struct frag, list));
+}
+
+/**
+ * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
+ * @frags:  Linked list of VBLK fragments
+ * @ldb:    Cache of the database structures
+ *
+ * Now that all the fragmented VBLKs have been collected, they must be added to
+ * the database for later use.
+ *
+ * Return:  TRUE   All the fragments we added successfully
+ *          FALSE  One or more of the fragments we invalid
+ */
+static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
+{
+	struct frag *f;
+	struct list_head *item;
+
+	BUG_ON (!frags);
+	BUG_ON (!ldb);
+
+	list_for_each (item, frags) {
+		f = list_entry (item, struct frag, list);
+
+		if (f->map != 0xFF) {
+			ldm_error ("VBLK group %d is incomplete (0x%02x).",
+				f->group, f->map);
+			return FALSE;
+		}
+
+		if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
+			return FALSE;		/* Already logged */
 	}
-	err = parse_privhead(data, ph);
-	if (err == 1)
-		err = create_partition(hd, first_part_minor, first_sector +
-				ph->config_start, ph->config_size);
-	put_dev_sector(sect);
-	return err;
+	return TRUE;
 }
 
 /**
- * validate_patition_table - check whether @dev is a dynamic disk
- * @dev:	device to test
+ * ldm_get_vblks - Read the on-disk database of VBLKs into memory
+ * @bdev:  Device holding the LDM Database
+ * @base:  Offset, into @bdev, of the database
+ * @ldb:   Cache of the database structures
  *
- * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
- * table with one or more entries of type 0x42 (the former Secure File System
- * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
- * If this succeeds we assume we have a dynamic disk, and not otherwise.
+ * To use the information from the VBLKs, they need to be read from the disk,
+ * unpacked and validated.  We cache them in @ldb according to their type.
  *
- * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
+ * Return:  TRUE   All the VBLKs were read successfully
+ *          FALSE  An error occurred
  */
-static int validate_partition_table(struct block_device *bdev)
+static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base,
+			   struct ldmdb *ldb)
 {
+	int size, perbuf, skip, finish, s, v, recs;
+	u8 *data = NULL;
 	Sector sect;
-	unsigned char *data;
-	struct partition *p;
-	int i, nr_sfs;
+	BOOL result = FALSE;
+	LIST_HEAD (frags);
 
-	data = read_dev_sector(bdev, 0, &sect);
-	if (!data)
-		return -1;
+	BUG_ON (!bdev);
+	BUG_ON (!ldb);
 
-	if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
-		ldm_debug("No MS-DOS partition found.\n");
-		goto no_msdos_partition;
-	}
-	nr_sfs = 0;
-	p = (struct partition*)(data + 0x01BE);
-	for (i = 0; i < 4; i++) {
-		if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
-			continue;
-		if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
-			nr_sfs++;
-			continue;
+	size   = ldb->vm.vblk_size;
+	perbuf = 512 / size;
+	skip   = ldb->vm.vblk_offset >> 9;		/* Bytes to sectors */
+	finish = (size * ldb->vm.last_vblk_seq) >> 9;
+
+	for (s = skip; s < finish; s++) {		/* For each sector */
+		data = read_dev_sector (bdev, base + OFF_VMDB + s, &sect);
+		if (!data) {
+			ldm_crit ("Disk read failed.");
+			goto out;
 		}
-		goto not_dynamic_disk;
+
+		for (v = 0; v < perbuf; v++, data+=size) {  /* For each vblk */
+			if (MAGIC_VBLK != BE32 (data)) {
+				ldm_error ("Expected to find a VBLK.");
+				goto out;
+			}
+
+			recs = BE16 (data + 0x0E);	/* Number of records */
+			if (recs == 1) {
+				if (!ldm_ldmdb_add (data, size, ldb))
+					goto out;	/* Already logged */
+			} else if (recs > 1) {
+				if (!ldm_frag_add (data, size, &frags))
+					goto out;	/* Already logged */
+			}
+			/* else Record is not in use, ignore it. */
+		}
+		put_dev_sector (sect);
+		data = NULL;
 	}
-	if (!nr_sfs)
-		goto not_dynamic_disk;
-	ldm_debug("Parsed partition table successfully.\n");
-	put_dev_sector(sect);
-	return 1;
-not_dynamic_disk:
-//	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
-no_msdos_partition:
-	put_dev_sector(sect);
-	return 0;
+
+	result = ldm_frag_commit (&frags, ldb);	/* Failures, already logged */
+out:
+	if (data)
+		put_dev_sector (sect);
+	ldm_frag_free (&frags);
+
+	return result;
 }
 
 /**
- * ldm_partition - find out whether a device is a dynamic disk and handle it
- * @hd:			gendisk structure in which to return the handled disk
- * @dev:		device we need to look at
- * @first_sector:	first sector within the device
- * @first_part_minor:	first minor number of partitions for the device
+ * ldm_free_vblks - Free a linked list of vblk's
+ * @lh:  Head of a linked list of struct vblk
  *
- * Description:
+ * Free a list of vblk's and free the memory used to maintain the list.
+ *
+ * Return:  none
+ */
+static void ldm_free_vblks (struct list_head *lh)
+{
+	struct list_head *item, *tmp;
+
+	BUG_ON (!lh);
+
+	list_for_each_safe (item, tmp, lh)
+		kfree (list_entry (item, struct vblk, list));
+}
+
+
+/**
+ * ldm_partition - Find out whether a device is a dynamic disk and handle it
+ * @hd:            gendisk structure in which to return the handled disk
+ * @bdev:          Device we need to look at
+ * @first_sector:  First sector within the device
+ * @first_minor:   First minor number of partitions for the device
  *
- * This determines whether the device @dev is a dynamic disk and if so creates
+ * This determines whether the device @bdev is a dynamic disk and if so creates
  * the partitions necessary in the gendisk structure pointed to by @hd.
  *
- * We create a dummy device 1, which contains the LDM database, we skip
- * devices 2-4 and then create each partition described by the LDM database
- * in sequence as devices 5 and following. For example, if the device is hda,
- * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
- * actual data containing partitions.
- *
- * Return values:
- *
- *	 1 if @dev is a dynamic disk and we handled it,
- *	 0 if @dev is not a dynamic disk,
- *	-1 if an error occured.
- */
-int ldm_partition(struct gendisk *hd, struct block_device *bdev,
-		unsigned long first_sector, int first_part_minor)
-{
-	struct privhead *ph  = NULL;
-	struct tocblock *toc = NULL;
-	struct vmdb     *vm  = NULL;
-	struct ldmdisk  *dk  = NULL;
-	unsigned long db_first;
-	int err;
+ * We create a dummy device 1, which contains the LDM database, and then create
+ * each partition described by the LDM database in sequence as devices 2+. For
+ * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3,
+ * and so on: the actual data containing partitions.
+ *
+ * Return:  1 Success, @bdev is a dynamic disk and we handled it
+ *          0 Success, @bdev is not a dynamic disk
+ *         -1 An error occurred before enough information had been read
+ *            Or @bdev is a dynamic disk, but it may be corrupted
+ */
+int ldm_partition (struct gendisk *hd, struct block_device *bdev,
+	unsigned long first_sector, int first_minor)
+{
+	struct ldmdb  *ldb;
+	unsigned long base;
+	int result = -1;
+
+	BUG_ON (!hd);
+	BUG_ON (!bdev);
 
-	if (!hd)
+	/* Look for signs of a Dynamic Disk */
+	if (!ldm_validate_partition_table (bdev))
 		return 0;
-	/* Check the partition table. */
-	err = validate_partition_table(bdev);
-	if (err != 1)
-		return err;
-	if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
-		goto no_mem;
-	/* Create the LDM database device. */
-	err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph);
-	if (err != 1)
-		goto out;
-	db_first = hd->part[first_part_minor].start_sect;
-	/* Check the backup privheads. */
-	err = validate_privheads(bdev, ph, db_first);
-	if (err != 1)
-		goto out;
-	/* Check the table of contents and its backups. */
-	if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
-		goto no_mem;
-	err = validate_tocblocks(bdev, toc, db_first);
-	if (err != 1)
-		goto out;
-	/* Check the vmdb. */
-	if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
-		goto no_mem;
-	err = validate_vmdb(bdev, vm, db_first);
-	if (err != 1)
-		goto out;
-	/* Find the object id for @dev in the LDM database. */
-	if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
-		goto no_mem;
-	err = get_disk_objid(bdev, vm, ph, dk, db_first);
-	if (err != 1)
+
+	ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
+	if (!ldb) {
+		ldm_crit ("Out of memory.");
 		goto out;
+	}
+
+	/* Parse and check privheads. */
+	if (!ldm_validate_privheads (bdev, first_sector, &ldb->ph, hd, first_minor))
+		goto out;		/* Already logged */
+
+	/* All further references are relative to base (database start). */
+	base = first_sector + ldb->ph.config_start;
+
+	/* Parse and check tocs and vmdb. */
+	if (!ldm_validate_tocblocks (bdev, base, ldb) ||
+	    !ldm_validate_vmdb      (bdev, base, ldb))
+	    	goto out;		/* Already logged */
+
+	/* Initialize vblk lists in ldmdb struct */
+	INIT_LIST_HEAD (&ldb->v_dgrp);
+	INIT_LIST_HEAD (&ldb->v_disk);
+	INIT_LIST_HEAD (&ldb->v_volu);
+	INIT_LIST_HEAD (&ldb->v_comp);
+	INIT_LIST_HEAD (&ldb->v_part);
+
+	if (!ldm_get_vblks (bdev, base, ldb)) {
+		ldm_crit ("Failed to read the VBLKs from the database.");
+		goto cleanup;
+	}
+
 	/* Finally, create the data partition devices. */
-	err = create_data_partitions(hd, first_sector, first_part_minor +
-			LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first);
-	if (err == 1)
-		ldm_debug("Parsed LDM database successfully.\n");
+	if (ldm_create_data_partitions (hd, first_sector, first_minor, ldb)) {
+		ldm_debug ("Parsed LDM database successfully.");
+		result = 1;
+	}
+	/* else Already logged */
+
+cleanup:
+	ldm_free_vblks (&ldb->v_dgrp);
+	ldm_free_vblks (&ldb->v_disk);
+	ldm_free_vblks (&ldb->v_volu);
+	ldm_free_vblks (&ldb->v_comp);
+	ldm_free_vblks (&ldb->v_part);
 out:
-	kfree(ph);
-	kfree(toc);
-	kfree(vm);
-	kfree(dk);
-	return err;
-no_mem:
-	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
-	err = -1;
-	goto out;
+	kfree (ldb);
+	return result;
 }
 
diff -urN linux-2.4.20-pre2/fs/partitions/ldm.h linux-2.4.20-pre3/fs/partitions/ldm.h
--- linux-2.4.20-pre2/fs/partitions/ldm.h	Thu Nov 22 11:48:07 2001
+++ linux-2.4.20-pre3/fs/partitions/ldm.h	Sat Aug 17 14:18:59 2002
@@ -1,10 +1,9 @@
-#ifndef _FS_PT_LDM_H_
-#define _FS_PT_LDM_H_
-/*
+/**
  * ldm - Part of the Linux-NTFS project.
  *
- * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ * Copyright (C) 2001      Anton Altaparmakov <aia21@cantab.net>
+ * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
@@ -23,16 +22,18 @@
  * in the file COPYING); if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
+#ifndef _FS_PT_LDM_H_
+#define _FS_PT_LDM_H_
+
 #include <linux/types.h>
+#include <linux/list.h>
+#include <linux/genhd.h>
+#include <linux/fs.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
-#include <linux/genhd.h>
 
-/* Borrowed from kernel.h. */
-#define LDM_PREFIX	"LDM: "	   /* Prefix our error messages with this. */
-#define LDM_CRIT	KERN_CRIT	LDM_PREFIX /* critical conditions */
-#define LDM_ERR		KERN_ERR	LDM_PREFIX /* error conditions */
-#define LDM_DEBUG	KERN_DEBUG	LDM_PREFIX /* debug-level messages */
+struct parsed_partitions;
 
 /* Magic numbers in CPU format. */
 #define MAGIC_VMDB	0x564D4442		/* VMDB */
@@ -41,41 +42,58 @@
 #define MAGIC_TOCBLOCK	0x544F43424C4F434B	/* TOCBLOCK */
 
 /* The defined vblk types. */
-#define VBLK_COMP		0x32		/* Component */
-#define VBLK_PART		0x33		/* Partition */
-#define VBLK_DSK1		0x34		/* Disk */
-#define VBLK_DSK2		0x44		/* Disk */
-#define VBLK_DGR1		0x35		/* Disk Group */
-#define VBLK_DGR2		0x45		/* Disk Group */
-#define VBLK_VOLU		0x51		/* Volume */
+#define VBLK_VOL5		0x51		/* Volume,     version 5 */
+#define VBLK_CMP3		0x32		/* Component,  version 3 */
+#define VBLK_PRT3		0x33		/* Partition,  version 3 */
+#define VBLK_DSK3		0x34		/* Disk,       version 3 */
+#define VBLK_DSK4		0x44		/* Disk,       version 4 */
+#define VBLK_DGR3		0x35		/* Disk Group, version 3 */
+#define VBLK_DGR4		0x45		/* Disk Group, version 4 */
+
+/* vblk flags indicating extra information will be present */
+#define	VBLK_FLAG_COMP_STRIPE	0x10
+#define	VBLK_FLAG_PART_INDEX	0x08
+#define	VBLK_FLAG_DGR3_IDS	0x08
+#define	VBLK_FLAG_DGR4_IDS	0x08
+#define	VBLK_FLAG_VOLU_ID1	0x08
+#define	VBLK_FLAG_VOLU_ID2	0x20
+#define	VBLK_FLAG_VOLU_SIZE	0x80
+#define	VBLK_FLAG_VOLU_DRIVE	0x02
+
+/* size of a vblk's static parts */
+#define VBLK_SIZE_HEAD		16
+#define VBLK_SIZE_CMP3		22		/* Name and version */
+#define VBLK_SIZE_DGR3		12
+#define VBLK_SIZE_DGR4		44
+#define VBLK_SIZE_DSK3		12
+#define VBLK_SIZE_DSK4		45
+#define VBLK_SIZE_PRT3		28
+#define VBLK_SIZE_VOL5		59
+
+/* component types */
+#define COMP_STRIPE		0x01		/* Stripe-set */
+#define COMP_BASIC		0x02		/* Basic disk */
+#define COMP_RAID		0x03		/* Raid-set */
 
 /* Other constants. */
-#define LDM_BLOCKSIZE		1024		/* Size of block in bytes. */
 #define LDM_DB_SIZE		2048		/* Size in sectors (= 1MiB). */
-#define LDM_FIRST_PART_OFFSET	4		/* Add this to first_part_minor
-						   to get to the first data
-						   partition device minor. */
 
-#define OFF_PRIVHEAD1		3		/* Offset of the first privhead
+#define OFF_PRIV1		6		/* Offset of the first privhead
 						   relative to the start of the
-						   device in units of
-						   LDM_BLOCKSIZE. */
+						   device in sectors */
 
-/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */
-#define OFF_PRIVHEAD2		928		/* Backup private headers. */
-#define OFF_PRIVHEAD3		1023
-
-#define OFF_TOCBLOCK1		0		/* Tables of contents. */
-#define OFF_TOCBLOCK2		1
-#define OFF_TOCBLOCK3		1022
-#define OFF_TOCBLOCK4		1023
-
-#define OFF_VMDB		8		/* List of partitions. */
-#define OFF_VBLK		9
-
-#define WIN2K_DYNAMIC_PARTITION		0x42	/* Formerly SFS (Landis). */
-#define WIN2K_EXTENDED_PARTITION	0x05	/* A standard extended
-						   partition. */
+/* Offsets to structures within the LDM Database in sectors. */
+#define OFF_PRIV2		1856		/* Backup private headers. */
+#define OFF_PRIV3		2047
+
+#define OFF_TOCB1		1		/* Tables of contents. */
+#define OFF_TOCB2		2
+#define OFF_TOCB3		2045
+#define OFF_TOCB4		2046
+
+#define OFF_VMDB		17		/* List of partitions. */
+
+#define WIN2K_DYNAMIC_PARTITION	0x42		/* Formerly SFS (Landis). */
 
 #define TOC_BITMAP1		"config"	/* Names of the two defined */
 #define TOC_BITMAP2		"log"		/* bitmaps in the TOCBLOCK. */
@@ -85,49 +103,42 @@
 #define BE32(x)			((u32)be32_to_cpu(get_unaligned((u32*)(x))))
 #define BE64(x)			((u64)be64_to_cpu(get_unaligned((u64*)(x))))
 
-/* Borrowed from msdos.c. */
+/* Borrowed from msdos.c */
 #define SYS_IND(p)		(get_unaligned(&(p)->sys_ind))
-#define NR_SECTS(p)		({ __typeof__((p)->nr_sects) __a =	\
-					get_unaligned(&(p)->nr_sects);	\
-					le32_to_cpu(__a);		\
-				})
-
-#define START_SECT(p)		({ __typeof__((p)->start_sect) __a =	\
-					get_unaligned(&(p)->start_sect);\
-					le32_to_cpu(__a);		\
-				})
 
-/* In memory LDM database structures. */
+struct frag {				/* VBLK Fragment handling */
+	struct list_head list;
+	u32		group;
+	u8		num;		/* Total number of records */
+	u8		rec;		/* This is record number n */
+	u8		map;		/* Which portions are in use */
+	u8		data[0];
+};
 
-#define DISK_ID_SIZE		64	/* Size in bytes. */
+/* In memory LDM database structures. */
 
-struct ldmdisk {
-	u64	obj_id;
-	u8	disk_id[DISK_ID_SIZE];
-};
+#define GUID_SIZE		16
 
-struct privhead	{			/* Offsets and sizes are in sectors. */
+struct privhead {			/* Offsets and sizes are in sectors. */
 	u16	ver_major;
 	u16	ver_minor;
 	u64	logical_disk_start;
 	u64	logical_disk_size;
 	u64	config_start;
 	u64	config_size;
-	u8	disk_id[DISK_ID_SIZE];
+	u8	disk_id[GUID_SIZE];
 };
 
 struct tocblock {			/* We have exactly two bitmaps. */
 	u8	bitmap1_name[16];
 	u64	bitmap1_start;
 	u64	bitmap1_size;
-	/*u64	bitmap1_flags;*/
 	u8	bitmap2_name[16];
 	u64	bitmap2_start;
 	u64	bitmap2_size;
-	/*u64	bitmap2_flags;*/
 };
 
-struct vmdb {
+struct vmdb {				/* VMDB: The database header */
 	u16	ver_major;
 	u16	ver_minor;
 	u32	vblk_size;
@@ -135,23 +146,76 @@
 	u32	last_vblk_seq;
 };
 
-struct vblk {
-	u8	name[64];
-	u8	vblk_type;
-	u64	obj_id;
+struct vblk_comp {			/* VBLK Component */
+	u8	state[16];
+	u64	parent_id;
+	u8	type;
+	u8	children;
+	u16	chunksize;
+};
+
+struct vblk_dgrp {			/* VBLK Disk Group */
+	u8	disk_id[64];
+};
+
+struct vblk_disk {			/* VBLK Disk */
+	u8	disk_id[GUID_SIZE];
+	u8	alt_name[128];
+};
+
+struct vblk_part {			/* VBLK Partition */
+	u64	start;
+	u64	size;			/* start, size and vol_off in sectors */
+	u64	volume_offset;
+	u64	parent_id;
 	u64	disk_id;
-	u64	start_sector;
-	u64	num_sectors;
+	u8	partnum;
+};
+
+struct vblk_volu {			/* VBLK Volume */
+	u8	volume_type[16];
+	u8	volume_state[16];
+	u8	guid[16];
+	u8	drive_hint[4];
+	u64	size;
+	u8	partition_type;
 };
 
-struct ldm_part {
-	struct list_head part_list;
-	unsigned long start;
-	unsigned long size;
+struct vblk_head {			/* VBLK standard header */
+	u32 group;
+	u16 rec;
+	u16 nrec;
+};
+
+struct vblk {				/* Generalised VBLK */
+	u8	name[64];
+	u64	obj_id;
+	u32	sequence;
+	u8	flags;
+	u8	type;
+	union {
+		struct vblk_comp comp;
+		struct vblk_dgrp dgrp;
+		struct vblk_disk disk;
+		struct vblk_part part;
+		struct vblk_volu volu;
+	} vblk;
+	struct list_head list;
+};
+
+struct ldmdb {				/* Cache of the database */
+	struct privhead ph;
+	struct tocblock toc;
+	struct vmdb     vm;
+	struct list_head v_dgrp;
+	struct list_head v_disk;
+	struct list_head v_volu;
+	struct list_head v_comp;
+	struct list_head v_part;
 };
 
-int ldm_partition(struct gendisk *hd, struct block_device *bdev,
-		unsigned long first_sector, int first_part_minor);
+int ldm_partition (struct gendisk *hd, struct block_device *bdev,
+	unsigned long first_sector, int first_minor);
 
 #endif /* _FS_PT_LDM_H_ */
 
diff -urN linux-2.4.20-pre2/fs/reiserfs/buffer2.c linux-2.4.20-pre3/fs/reiserfs/buffer2.c
--- linux-2.4.20-pre2/fs/reiserfs/buffer2.c	Sat Aug 17 14:18:27 2002
+++ linux-2.4.20-pre3/fs/reiserfs/buffer2.c	Sat Aug 17 14:18:59 2002
@@ -33,8 +33,7 @@
 			buffer_journal_dirty(bh) ? ' ' : '!');
     }
     run_task_queue(&tq_disk);
-    current->policy |= SCHED_YIELD;
-    schedule();
+    yield();
   }
   if (repeat_counter > 30000000) {
     reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ;
diff -urN linux-2.4.20-pre2/fs/reiserfs/journal.c linux-2.4.20-pre3/fs/reiserfs/journal.c
--- linux-2.4.20-pre2/fs/reiserfs/journal.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/fs/reiserfs/journal.c	Sat Aug 17 14:18:59 2002
@@ -151,8 +151,7 @@
   }
   bn = allocate_bitmap_node(p_s_sb) ;
   if (!bn) {
-    current->policy |= SCHED_YIELD ;
-    schedule() ;
+    yield();
     goto repeat ;
   }
   return bn ;
diff -urN linux-2.4.20-pre2/fs/smbfs/inode.c linux-2.4.20-pre3/fs/smbfs/inode.c
--- linux-2.4.20-pre2/fs/smbfs/inode.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre3/fs/smbfs/inode.c	Sat Aug 17 14:18:59 2002
@@ -43,6 +43,7 @@
 #endif
 
 #define SMB_TTL_DEFAULT 1000
+#define SMB_TIMEO_DEFAULT 30
 
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
@@ -277,6 +278,7 @@
 	{ "iocharset",	0, 'i' },
 	{ "codepage",	0, 'c' },
 	{ "ttl",	0, 't' },
+	{ "timeo",	0, 'o' },
 	{ NULL,		0, 0}
 };
 
@@ -330,6 +332,9 @@
 		case 't':
 			mnt->ttl = value;
 			break;
+		case 'o':
+			mnt->timeo = value;
+			break;
 		default:
 			printk ("smbfs: Unrecognized mount option %s\n",
 				optopt);
@@ -376,6 +381,8 @@
 
 	if (mnt->ttl != SMB_TTL_DEFAULT)
 		seq_printf(s, ",ttl=%d", mnt->ttl);
+	if (mnt->timeo != SMB_TIMEO_DEFAULT)
+		seq_printf(s, ",timeo=%d", mnt->timeo);
 
 	return 0;
 }
@@ -467,6 +474,7 @@
 		SMB_NLS_MAXNAMELEN);
 
 	mnt->ttl = SMB_TTL_DEFAULT;
+	mnt->timeo = SMB_TIMEO_DEFAULT;
 	if (ver == SMB_MOUNT_OLDVERSION) {
 		mnt->version = oldmnt->version;
 
diff -urN linux-2.4.20-pre2/fs/smbfs/proc.c linux-2.4.20-pre3/fs/smbfs/proc.c
--- linux-2.4.20-pre2/fs/smbfs/proc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/fs/smbfs/proc.c	Sat Aug 17 14:18:59 2002
@@ -33,9 +33,6 @@
    config option. */
 #define SMBFS_POSIX_UNLINK 1
 
-/* Allow smb_retry to be interrupted. */
-#define SMB_RETRY_INTR
-
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
 #define SMB_CMD(packet)  (*(packet+8))
 #define SMB_WCT(packet)  (*(packet+SMB_HEADER_LEN - 1))
@@ -715,28 +712,11 @@
 	/*
 	 * Wait for the new connection.
 	 */
-#ifdef SMB_RETRY_INTR
 	smb_unlock_server(server);
-	interruptible_sleep_on_timeout(&server->wait,  30*HZ);
+	interruptible_sleep_on_timeout(&server->wait, server->mnt->timeo*HZ);
 	smb_lock_server(server);
 	if (signal_pending(current))
 		printk(KERN_INFO "smb_retry: caught signal\n");
-#else
-	/*
-	 * We don't want to be interrupted. For example, what if 'current'
-	 * already has received a signal? sleep_on would terminate immediately
-	 * and smbmount would not be able to re-establish connection.
-	 *
-	 * smbmount should be able to reconnect later, but it can't because
-	 * it will get an -EIO on attempts to open the mountpoint!
-	 *
-	 * FIXME: go back to the interruptable version now that smbmount
-	 * can avoid -EIO on the mountpoint when reconnecting?
-	 */
-	smb_unlock_server(server);
-	sleep_on_timeout(&server->wait, 30*HZ);
-	smb_lock_server(server);
-#endif
 
 	/*
 	 * Check for a valid connection.
@@ -895,11 +875,7 @@
 int
 smb_wakeup(struct smb_sb_info *server)
 {
-#ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
-#else
-	wake_up(&server->wait);
-#endif
 	return 0;
 }
 
diff -urN linux-2.4.20-pre2/fs/smbfs/sock.c linux-2.4.20-pre3/fs/smbfs/sock.c
--- linux-2.4.20-pre2/fs/smbfs/sock.c	Tue Oct  2 17:03:34 2001
+++ linux-2.4.20-pre3/fs/smbfs/sock.c	Sat Aug 17 14:18:59 2002
@@ -12,6 +12,7 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
+#include <linux/poll.h>
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
@@ -305,6 +306,55 @@
 	}
 }
 
+/*
+ * Poll the server->socket to allow receives to time out.
+ * returns 0 when ok to continue, <0 on errors.
+ */
+static int
+smb_receive_poll(struct smb_sb_info *server)
+{
+	struct file *file = server->sock_file;
+	poll_table wait_table;
+	int result = 0;
+	int timeout = server->mnt->timeo * HZ;
+	int mask;
+
+	for (;;) {
+		poll_initwait(&wait_table);
+                set_current_state(TASK_INTERRUPTIBLE);
+
+		mask = file->f_op->poll(file, &wait_table);
+		if (mask & POLLIN) {
+			poll_freewait(&wait_table);
+			current->state = TASK_RUNNING;
+			break;
+		}
+
+		timeout = schedule_timeout(timeout);
+		poll_freewait(&wait_table);
+                set_current_state(TASK_RUNNING);
+
+		if (wait_table.error) {
+			result = wait_table.error;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			/* we got a signal (which?) tell the caller to
+			   try again (on all signals?). */
+			DEBUG1("got signal_pending()\n");
+			result = -ERESTARTSYS;
+			break;
+		}
+		if (!timeout) {
+			printk(KERN_WARNING "SMB server not responding\n");
+			result = -EIO;
+			break;
+		}
+	}
+	return result;
+}
+
 static int
 smb_send_raw(struct socket *socket, unsigned char *source, int length)
 {
@@ -332,13 +382,19 @@
 }
 
 static int
-smb_receive_raw(struct socket *socket, unsigned char *target, int length)
+smb_receive_raw(struct smb_sb_info *server, unsigned char *target, int length)
 {
 	int result;
 	int already_read = 0;
+	struct socket *socket = server_sock(server);
 
 	while (already_read < length)
 	{
+		result = smb_receive_poll(server);
+		if (result < 0) {
+			DEBUG1("poll error = %d\n", -result);
+			return result;
+		}
 		result = _recvfrom(socket,
 				   (void *) (target + already_read),
 				   length - already_read, 0);
@@ -358,7 +414,7 @@
 }
 
 static int
-smb_get_length(struct socket *socket, unsigned char *header)
+smb_get_length(struct smb_sb_info *server, unsigned char *header)
 {
 	int result;
 	unsigned char peek_buf[4];
@@ -367,7 +423,7 @@
       re_recv:
 	fs = get_fs();
 	set_fs(get_ds());
-	result = smb_receive_raw(socket, peek_buf, 4);
+	result = smb_receive_raw(server, peek_buf, 4);
 	set_fs(fs);
 
 	if (result < 0)
@@ -415,12 +471,11 @@
 static int
 smb_receive(struct smb_sb_info *server)
 {
-	struct socket *socket = server_sock(server);
 	unsigned char * packet = server->packet;
 	int len, result;
 	unsigned char peek_buf[4];
 
-	result = smb_get_length(socket, peek_buf);
+	result = smb_get_length(server, peek_buf);
 	if (result < 0)
 		goto out;
 	len = result;
@@ -442,7 +497,7 @@
 		server->packet_size = new_len;
 	}
 	memcpy(packet, peek_buf, 4);
-	result = smb_receive_raw(socket, packet + 4, len);
+	result = smb_receive_raw(server, packet + 4, len);
 	if (result < 0)
 	{
 		VERBOSE("receive error: %d\n", result);
diff -urN linux-2.4.20-pre2/fs/ufs/truncate.c linux-2.4.20-pre3/fs/ufs/truncate.c
--- linux-2.4.20-pre2/fs/ufs/truncate.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre3/fs/ufs/truncate.c	Sat Aug 17 14:18:59 2002
@@ -448,10 +448,7 @@
 		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
 			ufs_sync_inode (inode);
 		run_task_queue(&tq_disk);
-		current->policy |= SCHED_YIELD;
-		schedule ();
-
-
+		yield();
 	}
 	offset = inode->i_size & uspi->s_fshift;
 	if (offset) {
diff -urN linux-2.4.20-pre2/include/asm-alpha/semaphore.h linux-2.4.20-pre3/include/asm-alpha/semaphore.h
--- linux-2.4.20-pre2/include/asm-alpha/semaphore.h	Tue Nov 20 15:49:31 2001
+++ linux-2.4.20-pre3/include/asm-alpha/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -80,6 +80,11 @@
 extern void up(struct semaphore *);
 extern void __up_wakeup(struct semaphore *);
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 /*
  * Hidden out of line code is fun, but extremely messy.  Rely on newer
  * compilers to do a respectable job with this.  The contention cases
diff -urN linux-2.4.20-pre2/include/asm-arm/semaphore.h linux-2.4.20-pre3/include/asm-arm/semaphore.h
--- linux-2.4.20-pre2/include/asm-arm/semaphore.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.20-pre3/include/asm-arm/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -125,4 +125,9 @@
 	__up_op(sem, __up_wakeup);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -urN linux-2.4.20-pre2/include/asm-cris/etraxgpio.h linux-2.4.20-pre3/include/asm-cris/etraxgpio.h
--- linux-2.4.20-pre2/include/asm-cris/etraxgpio.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-cris/etraxgpio.h	Sat Aug 17 14:18:59 2002
@@ -1,4 +1,4 @@
-/* $Id: etraxgpio.h,v 1.7 2002/04/10 11:55:50 johana Exp $ */
+/* $Id: etraxgpio.h,v 1.8 2002/06/17 15:53:07 johana Exp $ */
 /*
  * The following devices are accessable using this driver using
  * GPIO_MAJOR (120) and a couple of minor numbers:
@@ -25,7 +25,7 @@
 
 /* supported ioctl _IOC_NR's */
 
-#define IO_READBITS  0x1  /* read and return current port bits */
+#define IO_READBITS  0x1  /* read and return current port bits (obsolete) */
 #define IO_SETBITS   0x2  /* set the bits marked by 1 in the argument */
 #define IO_CLRBITS   0x3  /* clear the bits marked by 1 in the argument */
 
@@ -40,11 +40,11 @@
                               * 0=off, 1=green, 2=red, 3=yellow */
 
 /* GPIO direction ioctl's */
-#define IO_READDIR    0x8  /* Read direction 0=input 1=output */
+#define IO_READDIR    0x8  /* Read direction 0=input 1=output  (obsolete) */
 #define IO_SETINPUT   0x9  /* Set direction for bits set, 0=unchanged 1=input, 
-                              returns mask with current inputs */
+                              returns mask with current inputs (obsolete) */
 #define IO_SETOUTPUT  0xA  /* Set direction for bits set, 0=unchanged 1=output,
-                              returns mask with current outputs */
+                              returns mask with current outputs (obsolete)*/
 
 /* LED ioctl extended */
 #define IO_LED_SETBIT 0xB
@@ -63,5 +63,19 @@
 #define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \
   ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) )
 
+/* The following 4 ioctl's take a pointer as argument and handles
+ * 32 bit ports (port G) properly.
+ * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT
+ */
+#define IO_READ_INBITS   0x10 /* *arg is result of reading the input pins */
+#define IO_READ_OUTBITS  0x11 /* *arg is result of reading the output shadow */
+#define IO_SETGET_INPUT  0x12 /* bits set in *arg is set to input,
+                               * *arg updated with current input pins.
+                               */
+#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output,
+                               * *arg updated with current output pins.
+                               */
+
+
 
 #endif
diff -urN linux-2.4.20-pre2/include/asm-cris/etraxvirtex.h linux-2.4.20-pre3/include/asm-cris/etraxvirtex.h
--- linux-2.4.20-pre2/include/asm-cris/etraxvirtex.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/include/asm-cris/etraxvirtex.h	Sat Aug 17 14:18:59 2002
@@ -0,0 +1,35 @@
+/* $Id: etraxvirtex.h,v 1.1 2002/06/25 10:01:05 stefanl Exp $ */
+
+#ifndef _LINUX_ETRAXVIRTEX_FPGA_H
+#define _LINUX_ETRAXVIRTEX_FPGA_H
+
+/* etraxvirtex_fpga _IOC_TYPE, bits 8 to 15 in ioctl cmd */
+
+#define ETRAXVIRTEX_FPGA_IOCTYPE 45
+
+/* supported ioctl _IOC_NR's */
+
+/* in write operations, the argument contains both virtex
+ * register and value.
+ */
+
+#define VIRTEX_FPGA_WRITEARG(reg, value) (((reg) << 16) | (value))
+#define VIRTEX_FPGA_READARG(reg) ((reg) << 16)
+
+#define VIRTEX_FPGA_ARGREG(arg) (((arg) >> 16) & 0x0fff)
+#define VIRTEX_FPGA_ARGVALUE(arg) ((arg) & 0xffff)
+
+#define VIRTEX_FPGA_WRITEREG 0x1   /* write to an (FPGA implemented) register */
+#define VIRTEX_FPGA_READREG  0x2   /* read from an (FPGA implemented register */
+
+/*
+EXAMPLE usage:
+
+    virtex_arg = VIRTEX_FPGA_WRITEARG( reg, val);
+    ioctl(fd, _IO(ETRAXVIRTEX_FPGA_IOCTYPE, VIRTEX_FPGA_WRITEREG), virtex_arg);
+
+    virtex_arg = VIRTEX_FPGA_READARG( reg);
+    val = ioctl(fd, _IO(ETRAXVIRTEX_FPGA_IOCTYPE, VIRTEX_FPGA_READREG), virtex_arg);
+
+*/
+#endif
diff -urN linux-2.4.20-pre2/include/asm-cris/fasttimer.h linux-2.4.20-pre3/include/asm-cris/fasttimer.h
--- linux-2.4.20-pre2/include/asm-cris/fasttimer.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/include/asm-cris/fasttimer.h	Sat Aug 17 14:18:59 2002
@@ -0,0 +1,47 @@
+/* $Id: fasttimer.h,v 1.2 2002/05/28 17:45:34 johana Exp $
+ * linux/include/asm-cris/fasttimer.h
+ *
+ * Fast timers for ETRAX100LX
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ * Copyright (C) 2000, 2002 Axis Communications AB
+ */
+#include <linux/config.h>
+#include <linux/time.h> /* struct timeval */
+#include <linux/timex.h>
+
+/* The timer0 values gives 52us resolution (1/19200) or higher 
+ * but interrupts at HZ 
+ */
+/* We use timer1 to generate interrupts at desired times. */
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+
+typedef void fast_timer_function_type(unsigned long);
+
+struct fast_timer{ /* Close to timer_list */
+  struct fast_timer *next;
+  struct fast_timer *prev;
+  struct timeval tv_set;
+  struct timeval tv_expires;
+  unsigned long delay_us;
+  fast_timer_function_type *function;
+  unsigned long data;
+  const char *name;
+};
+
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name);
+
+int del_fast_timer(struct fast_timer * t);
+/* return 1 if deleted */
+
+
+void schedule_usleep(unsigned long us);
+
+
+void fast_timer_init(void);
+
+#endif
diff -urN linux-2.4.20-pre2/include/asm-cris/rtc.h linux-2.4.20-pre3/include/asm-cris/rtc.h
--- linux-2.4.20-pre2/include/asm-cris/rtc.h	Tue May  1 16:05:00 2001
+++ linux-2.4.20-pre3/include/asm-cris/rtc.h	Sat Aug 17 14:18:59 2002
@@ -1,55 +1,86 @@
-/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */
+/* $Id: rtc.h,v 1.5 2002/08/14 11:04:10 sebsjo Exp $ */
+
+#ifndef __RTC_H__
+#define __RTC_H__
 
-#ifndef RTC_H
-#define RTC_H
 
 #include <linux/config.h>
 
-/* Dallas DS1302 clock/calendar register numbers */
+#ifdef CONFIG_ETRAX_DS1302
+   /* Dallas DS1302 clock/calendar register numbers. */
+#  define RTC_SECONDS      0
+#  define RTC_MINUTES      1
+#  define RTC_HOURS        2
+#  define RTC_DAY_OF_MONTH 3
+#  define RTC_MONTH        4
+#  define RTC_WEEKDAY      5
+#  define RTC_YEAR         6
+#  define RTC_CONTROL      7
+
+   /* Bits in CONTROL register. */
+#  define RTC_CONTROL_WRITEPROTECT 	0x80
+#  define RTC_TRICKLECHARGER 		8
+  
+  /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */
+#  define RTC_TCR_PATTERN 	0xA0	/* 1010xxxx */
+#  define RTC_TCR_1DIOD 	0x04	/* xxxx01xx */
+#  define RTC_TCR_2DIOD 	0x08	/* xxxx10xx */
+#  define RTC_TCR_DISABLED 	0x00	/* xxxxxx00 Disabled */
+#  define RTC_TCR_2KOHM 	0x01	/* xxxxxx01 2KOhm */
+#  define RTC_TCR_4KOHM 	0x02	/* xxxxxx10 4kOhm */
+#  define RTC_TCR_8KOHM 	0x03	/* xxxxxx11 8kOhm */
+
+#elif defined(CONFIG_ETRAX_PCF8563)
+   /* I2C bus slave registers. */
+#  define RTC_I2C_READ		0xa3
+#  define RTC_I2C_WRITE		0xa2
+
+   /* Phillips PCF8563 registers. */
+#  define RTC_CONTROL1		0x00		/* Control/Status register 1. */
+#  define RTC_CONTROL2		0x01		/* Control/Status register 2. */
+#  define RTC_CLOCKOUT_FREQ	0x0d		/* CLKOUT frequency. */
+#  define RTC_TIMER_CONTROL	0x0e		/* Timer control. */
+#  define RTC_TIMER_CNTDOWN	0x0f		/* Timer countdown. */
+
+   /* BCD encoded clock registers. */
+#  define RTC_SECONDS		0x02
+#  define RTC_MINUTES		0x03
+#  define RTC_HOURS		0x04
+#  define RTC_DAY_OF_MONTH	0x05
+#  define RTC_WEEKDAY		0x06	/* Not coded in BCD! */
+#  define RTC_MONTH		0x07
+#  define RTC_YEAR		0x08
+#  define RTC_MINUTE_ALARM	0x09
+#  define RTC_HOUR_ALARM	0x0a
+#  define RTC_DAY_ALARM		0x0b
+#  define RTC_WEEKDAY_ALARM 0x0c
 
-#define RTC_SECONDS 0
-#define RTC_MINUTES 1
-#define RTC_HOURS 2
-#define RTC_DAY_OF_MONTH 3
-#define RTC_MONTH 4
-#define RTC_WEEKDAY 5
-#define RTC_YEAR 6
-#define RTC_CONTROL 7
-
-/* Bits in CONTROL register */
-#define RTC_CONTROL_WRITEPROTECT 0x80
-#define RTC_TRICKLECHARGER 8
-/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */
-#define   RTC_TCR_PATTERN 0xA0 /* 1010xxxx */
-#define   RTC_TCR_1DIOD 0x04 /* xxxx01xx */
-#define   RTC_TCR_2DIOD 0x08 /* xxxx10xx */
-#define   RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */
-#define   RTC_TCR_2KOHM 0x01      /* xxxxxx01 2KOhm */
-#define   RTC_TCR_4KOHM 0x02      /* xxxxxx10 4kOhm */
-#define   RTC_TCR_8KOHM 0x03      /* xxxxxx11 8kOhm */
+#endif
 
 #ifdef CONFIG_ETRAX_DS1302
-#define CMOS_READ(x) ds1302_readreg(x)
-#define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
-#define RTC_INIT() ds1302_init()
+#  define CMOS_READ(x) ds1302_readreg(x)
+#  define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
+#  define RTC_INIT() ds1302_init()
+#elif defined(CONFIG_ETRAX_PCF8563)
+#  define CMOS_READ(x) i2c_readreg(RTC_I2C_READ, x)
+#  define CMOS_WRITE(val,reg) i2c_writereg(RTC_I2C_WRITE,reg,val)
+#  define RTC_INIT() pcf8563_init()
 #else
-/* no RTC configured so we shouldn't try to access any */
-#define CMOS_READ(x) 42
-#define CMOS_WRITE(x,y)
-#define RTC_INIT() (-1)
+  /* No RTC configured so we shouldn't try to access any. */
+#  define CMOS_READ(x) 42
+#  define CMOS_WRITE(x,y)
+#  define RTC_INIT() (-1)
 #endif
 
-/* conversions to and from the stupid RTC internal format */
-
-#define BCD_TO_BIN(x) x = (((x & 0xf0) >> 3) * 5 + (x & 0xf))
-#define BIN_TO_BCD(x) x = (x % 10) | ((x / 10) << 4) 
+/* Conversions to and from the RTC BCD encoded format. */
+#define BCD_TO_BIN(x) ((x)=((x)&15) + ((x)>>4)*10)
+#define BIN_TO_BCD(x) ((x)=(((x)/10)<<4) + (x)%10)
 
 /*
  * The struct used to pass data via the following ioctl. Similar to the
  * struct tm in <time.h>, but it needs to be here so that the kernel 
  * source is self contained, allowing cross-compiles, etc. etc.
  */
-
 struct rtc_time {
 	int tm_sec;
 	int tm_min;
@@ -62,14 +93,18 @@
 	int tm_isdst;
 };
 
-/*
- * ioctl calls that are permitted to the /dev/rtc interface
- */
-
-#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
-#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
-#define RTC_SET_CHARGE  _IOW('p', 0x0b, int) /* Set CHARGE mode    */
-
+/* ioctl() calls that are permitted to the /dev/rtc interface. */
+#ifdef CONFIG_ETRAX_DS1302
+#  define DS1302_MAGIC 'p'
+#  define RTC_RD_TIME		_IOR(DS1302_MAGIC, 0x09, struct rtc_time) 	/* Read RTC time. */
+#  define RTC_SET_TIME		_IOW(DS1302_MAGIC, 0x0a, struct rtc_time) 	/* Set RTC time. */
+#  define RTC_SET_CHARGE  	_IOW(DS1302_MAGIC, 0x0b, int) 				/* Set CHARGE mode. */
+#elif defined(CONFIG_ETRAX_PCF8563)
+#  define PCF8563_MAGIC 'T'
+#  define RTC_RD_TIME		_IOR(PCF8563_MAGIC, 0x01, struct rtc_time)	/* Read RTC time. */
+#  define RTC_SET_TIME		_IOW(PCF8563_MAGIC, 0x02, struct rtc_time)	/* Set RTC time. */
+#  define RTC_SET_CHARGE  	_IOW(PCF8563_MAGIC, 0x03, int) 		
+#  define RTC_MAX_IOCTL 3
 #endif
 
-
+#endif /* __RTC_H__ */
diff -urN linux-2.4.20-pre2/include/asm-cris/semaphore.h linux-2.4.20-pre3/include/asm-cris/semaphore.h
--- linux-2.4.20-pre2/include/asm-cris/semaphore.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.20-pre3/include/asm-cris/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -158,4 +158,9 @@
 	}
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return sem->count;
+}
+
 #endif
diff -urN linux-2.4.20-pre2/include/asm-i386/kmap_types.h linux-2.4.20-pre3/include/asm-i386/kmap_types.h
--- linux-2.4.20-pre2/include/asm-i386/kmap_types.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/asm-i386/kmap_types.h	Sat Aug 17 14:18:59 2002
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -urN linux-2.4.20-pre2/include/asm-i386/pgtable-2level.h linux-2.4.20-pre3/include/asm-i386/pgtable-2level.h
--- linux-2.4.20-pre2/include/asm-i386/pgtable-2level.h	Thu Jul 26 13:40:32 2001
+++ linux-2.4.20-pre3/include/asm-i386/pgtable-2level.h	Sat Aug 17 14:18:59 2002
@@ -40,6 +40,8 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_atomic(pteptr, pteval) (*(pteptr) = pteval)
+
 /*
  * (pmds are folded into pgds so this doesnt get actually called,
  * but the define is needed for a generic inline function.)
diff -urN linux-2.4.20-pre2/include/asm-i386/pgtable-3level.h linux-2.4.20-pre3/include/asm-i386/pgtable-3level.h
--- linux-2.4.20-pre2/include/asm-i386/pgtable-3level.h	Thu Jul 26 13:40:32 2001
+++ linux-2.4.20-pre3/include/asm-i386/pgtable-3level.h	Sat Aug 17 14:18:59 2002
@@ -53,6 +53,9 @@
 		set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
 #define set_pgd(pgdptr,pgdval) \
 		set_64bit((unsigned long long *)(pgdptr),pgd_val(pgdval))
+#define set_pte_atomic(pteptr,pteval) \
+		set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
+
 
 /*
  * Pentium-II erratum A13: in PAE mode we explicitly have to flush
diff -urN linux-2.4.20-pre2/include/asm-i386/pgtable.h linux-2.4.20-pre3/include/asm-i386/pgtable.h
--- linux-2.4.20-pre2/include/asm-i386/pgtable.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-i386/pgtable.h	Sat Aug 17 14:18:59 2002
@@ -347,6 +347,9 @@
 #define pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
+struct page;
+int change_page_attr(struct page *, int, pgprot_t prot);
+
 #endif /* !__ASSEMBLY__ */
 
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff -urN linux-2.4.20-pre2/include/asm-i386/semaphore.h linux-2.4.20-pre3/include/asm-i386/semaphore.h
--- linux-2.4.20-pre2/include/asm-i386/semaphore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-i386/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -213,5 +213,10 @@
 		:"memory");
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
 #endif
diff -urN linux-2.4.20-pre2/include/asm-ia64/semaphore.h linux-2.4.20-pre3/include/asm-ia64/semaphore.h
--- linux-2.4.20-pre2/include/asm-ia64/semaphore.h	Fri Nov  9 14:26:17 2001
+++ linux-2.4.20-pre3/include/asm-ia64/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -117,4 +117,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_IA64_SEMAPHORE_H */
diff -urN linux-2.4.20-pre2/include/asm-m68k/io.h linux-2.4.20-pre3/include/asm-m68k/io.h
--- linux-2.4.20-pre2/include/asm-m68k/io.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.20-pre3/include/asm-m68k/io.h	Sat Aug 17 14:18:59 2002
@@ -286,6 +286,11 @@
 #define IOMAP_NOCACHE_NONSER		2
 #define IOMAP_WRITETHROUGH		3
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void iounmap(void *addr);
 
 extern void *__ioremap(unsigned long physaddr, unsigned long size,
diff -urN linux-2.4.20-pre2/include/asm-m68k/pci.h linux-2.4.20-pre3/include/asm-m68k/pci.h
--- linux-2.4.20-pre2/include/asm-m68k/pci.h	Wed May 16 10:31:27 2001
+++ linux-2.4.20-pre3/include/asm-m68k/pci.h	Sat Aug 17 14:18:59 2002
@@ -48,4 +48,10 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
 #endif /* _ASM_M68K_PCI_H */
diff -urN linux-2.4.20-pre2/include/asm-m68k/semaphore.h linux-2.4.20-pre3/include/asm-m68k/semaphore.h
--- linux-2.4.20-pre2/include/asm-m68k/semaphore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-m68k/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -182,6 +182,12 @@
 		: "memory");
 }
 
+
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif
diff -urN linux-2.4.20-pre2/include/asm-m68k/types.h linux-2.4.20-pre3/include/asm-m68k/types.h
--- linux-2.4.20-pre2/include/asm-m68k/types.h	Mon Nov 27 18:00:49 2000
+++ linux-2.4.20-pre3/include/asm-m68k/types.h	Sat Aug 17 14:18:59 2002
@@ -49,9 +49,10 @@
 
 #define BITS_PER_LONG 32
 
-/* DMA addresses are 32-bits wide */
+/* DMA addresses are always 32-bits wide */
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.20-pre2/include/asm-mips/kmap_types.h linux-2.4.20-pre3/include/asm-mips/kmap_types.h
--- linux-2.4.20-pre2/include/asm-mips/kmap_types.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-mips/kmap_types.h	Sat Aug 17 14:18:59 2002
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -urN linux-2.4.20-pre2/include/asm-mips/semaphore.h linux-2.4.20-pre3/include/asm-mips/semaphore.h
--- linux-2.4.20-pre2/include/asm-mips/semaphore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-mips/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -194,4 +194,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_SEMAPHORE_H */
diff -urN linux-2.4.20-pre2/include/asm-mips64/semaphore.h linux-2.4.20-pre3/include/asm-mips64/semaphore.h
--- linux-2.4.20-pre2/include/asm-mips64/semaphore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-mips64/semaphore.h	Sat Aug 17 14:18:59 2002
@@ -170,4 +170,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* _ASM_SEMAPHORE_H */
diff -urN linux-2.4.20-pre2/include/asm-ppc/kmap_types.h linux-2.4.20-pre3/include/asm-ppc/kmap_types.h
--- linux-2.4.20-pre2/include/asm-ppc/kmap_types.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/asm-ppc/kmap_types.h	Sat Aug 17 14:19:00 2002
@@ -7,7 +7,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -urN linux-2.4.20-pre2/include/asm-ppc/semaphore.h linux-2.4.20-pre3/include/asm-ppc/semaphore.h
--- linux-2.4.20-pre2/include/asm-ppc/semaphore.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre3/include/asm-ppc/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -133,6 +133,11 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_PPC_SEMAPHORE_H) */
diff -urN linux-2.4.20-pre2/include/asm-ppc64/semaphore.h linux-2.4.20-pre3/include/asm-ppc64/semaphore.h
--- linux-2.4.20-pre2/include/asm-ppc64/semaphore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/asm-ppc64/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -130,6 +130,11 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_PPC64_SEMAPHORE_H) */
diff -urN linux-2.4.20-pre2/include/asm-s390/semaphore.h linux-2.4.20-pre3/include/asm-s390/semaphore.h
--- linux-2.4.20-pre2/include/asm-s390/semaphore.h	Tue Apr 17 17:19:31 2001
+++ linux-2.4.20-pre3/include/asm-s390/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -92,4 +92,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -urN linux-2.4.20-pre2/include/asm-s390x/semaphore.h linux-2.4.20-pre3/include/asm-s390x/semaphore.h
--- linux-2.4.20-pre2/include/asm-s390x/semaphore.h	Tue Apr 17 17:19:31 2001
+++ linux-2.4.20-pre3/include/asm-s390x/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -92,4 +92,9 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
diff -urN linux-2.4.20-pre2/include/asm-sh/semaphore.h linux-2.4.20-pre3/include/asm-sh/semaphore.h
--- linux-2.4.20-pre2/include/asm-sh/semaphore.h	Sat Sep  8 12:29:09 2001
+++ linux-2.4.20-pre3/include/asm-sh/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -135,5 +135,10 @@
 		__up(sem);
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif
 #endif /* __ASM_SH_SEMAPHORE_H */
diff -urN linux-2.4.20-pre2/include/asm-sparc/kmap_types.h linux-2.4.20-pre3/include/asm-sparc/kmap_types.h
--- linux-2.4.20-pre2/include/asm-sparc/kmap_types.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/asm-sparc/kmap_types.h	Sat Aug 17 14:19:00 2002
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -urN linux-2.4.20-pre2/include/asm-sparc/semaphore.h linux-2.4.20-pre3/include/asm-sparc/semaphore.h
--- linux-2.4.20-pre2/include/asm-sparc/semaphore.h	Tue Oct 30 15:08:11 2001
+++ linux-2.4.20-pre3/include/asm-sparc/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -213,6 +213,11 @@
 	: "g3", "g4", "g7", "memory", "cc");
 }	
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_SPARC_SEMAPHORE_H) */
diff -urN linux-2.4.20-pre2/include/asm-sparc64/semaphore.h linux-2.4.20-pre3/include/asm-sparc64/semaphore.h
--- linux-2.4.20-pre2/include/asm-sparc64/semaphore.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre3/include/asm-sparc64/semaphore.h	Sat Aug 17 14:19:00 2002
@@ -226,6 +226,11 @@
 	: "g5", "g7", "memory", "cc");
 }
 
+static inline int sem_getcount(struct semaphore *sem)
+{
+	return atomic_read(&sem->count);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* !(_SPARC64_SEMAPHORE_H) */
diff -urN linux-2.4.20-pre2/include/linux/elevator.h linux-2.4.20-pre3/include/linux/elevator.h
--- linux-2.4.20-pre2/include/linux/elevator.h	Thu Feb 15 16:58:34 2001
+++ linux-2.4.20-pre3/include/linux/elevator.h	Sat Aug 17 14:19:01 2002
@@ -18,7 +18,6 @@
 	int write_latency;
 
 	elevator_merge_fn *elevator_merge_fn;
-	elevator_merge_cleanup_fn *elevator_merge_cleanup_fn;
 	elevator_merge_req_fn *elevator_merge_req_fn;
 
 	unsigned int queue_ID;
@@ -81,23 +80,23 @@
 	return latency;
 }
 
+#define ELV_LINUS_SEEK_COST	16
+
 #define ELEVATOR_NOOP							\
 ((elevator_t) {								\
 	0,				/* read_latency */		\
 	0,				/* write_latency */		\
 									\
 	elevator_noop_merge,		/* elevator_merge_fn */		\
-	elevator_noop_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
 	elevator_noop_merge_req,	/* elevator_merge_req_fn */	\
 	})
 
 #define ELEVATOR_LINUS							\
 ((elevator_t) {								\
-	8192,				/* read passovers */		\
-	16384,				/* write passovers */		\
+	2048,				/* read passovers */		\
+	8192,				/* write passovers */		\
 									\
 	elevator_linus_merge,		/* elevator_merge_fn */		\
-	elevator_linus_merge_cleanup,	/* elevator_merge_cleanup_fn */	\
 	elevator_linus_merge_req,	/* elevator_merge_req_fn */	\
 	})
 
diff -urN linux-2.4.20-pre2/include/linux/fs.h linux-2.4.20-pre3/include/linux/fs.h
--- linux-2.4.20-pre2/include/linux/fs.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/linux/fs.h	Sat Aug 17 14:19:01 2002
@@ -595,6 +595,7 @@
 	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 
 	struct fasync_struct *	fl_fasync; /* for lease break notifications */
+	unsigned long fl_break_time;	/* for nonblocking lease breaks */
 
 	union {
 		struct nfs_lock_info	nfs_fl;
@@ -1051,7 +1052,7 @@
 
 static inline int get_lease(struct inode *inode, unsigned int mode)
 {
-	if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
+	if (inode->i_flock)
 		return __get_lease(inode, mode);
 	return 0;
 }
diff -urN linux-2.4.20-pre2/include/linux/nfs_xdr.h linux-2.4.20-pre3/include/linux/nfs_xdr.h
--- linux-2.4.20-pre2/include/linux/nfs_xdr.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/linux/nfs_xdr.h	Sat Aug 17 14:19:01 2002
@@ -65,8 +65,8 @@
 	struct nfs_fh *		fh;
 	__u64			offset;
 	__u32			count;
-	unsigned int            nriov;
-	struct iovec            iov[NFS_READ_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_readres {
@@ -84,8 +84,8 @@
 	__u64			offset;
 	__u32			count;
 	enum nfs3_stable_how	stable;
-	unsigned int		nriov;
-	struct iovec		iov[NFS_WRITE_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_writeverf {
@@ -162,8 +162,8 @@
 struct nfs_readdirargs {
 	struct nfs_fh *		fh;
 	__u32			cookie;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs_diropok {
@@ -173,18 +173,8 @@
 
 struct nfs_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readlinkres {
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readdirres {
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_sattrargs {
@@ -259,9 +249,9 @@
 	struct nfs_fh *		fh;
 	__u64			cookie;
 	__u32			verf[2];
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
+	unsigned int            count;
+	struct page **		pages;
 };
 
 struct nfs3_diropres {
@@ -277,14 +267,8 @@
 
 struct nfs3_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs3_readlinkres {
-	struct nfs_fattr *	fattr;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_renameres {
@@ -300,8 +284,6 @@
 struct nfs3_readdirres {
 	struct nfs_fattr *	dir_attr;
 	__u32 *			verf;
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
 };
 
@@ -319,15 +301,15 @@
 	int	(*lookup)  (struct inode *, struct qstr *,
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*access)  (struct inode *, int , int);
-	int	(*readlink)(struct inode *, void *, unsigned int);
+	int	(*readlink)(struct inode *, struct page *);
 	int	(*read)    (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, int *eofp);
+			    int, unsigned int, unsigned int,
+			    struct page *, int *eofp);
 	int	(*write)   (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, struct nfs_writeverf *verfp);
+			    int, unsigned int, unsigned int,
+			    struct page *, struct nfs_writeverf *verfp);
 	int	(*commit)  (struct inode *, struct nfs_fattr *,
 			    unsigned long, unsigned int);
 	int	(*create)  (struct inode *, struct qstr *, struct iattr *,
@@ -346,7 +328,7 @@
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*rmdir)   (struct inode *, struct qstr *);
 	int	(*readdir) (struct inode *, struct rpc_cred *,
-			    u64, void *, unsigned int, int);
+			    u64, struct page *, unsigned int, int);
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
diff -urN linux-2.4.20-pre2/include/linux/pci.h linux-2.4.20-pre3/include/linux/pci.h
--- linux-2.4.20-pre2/include/linux/pci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre3/include/linux/pci.h	Sat Aug 17 14:19:01 2002
@@ -493,7 +493,7 @@
 
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
-int pcibios_enable_device(struct pci_dev *);
+int pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
@@ -559,6 +559,7 @@
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 
 int pci_enable_device(struct pci_dev *dev);
+int pci_enable_device_bars(struct pci_dev *dev, int mask);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
@@ -648,6 +649,7 @@
 { return NULL; }
 
 static inline void pci_set_master(struct pci_dev *dev) { }
+static inline int pci_enable_device_bars(struct pci_dev *dev, int mask) { return -EBUSY; }
 static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
 static inline void pci_disable_device(struct pci_dev *dev) { }
 static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; }
diff -urN linux-2.4.20-pre2/include/linux/pci_ids.h linux-2.4.20-pre3/include/linux/pci_ids.h
--- linux-2.4.20-pre2/include/linux/pci_ids.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/linux/pci_ids.h	Sat Aug 17 14:19:01 2002
@@ -1059,6 +1059,7 @@
 #define PCI_DEVICE_ID_EICON_DIVA20PRO_U	0xe003
 #define PCI_DEVICE_ID_EICON_DIVA20_U	0xe004
 #define PCI_DEVICE_ID_EICON_DIVA201	0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202	0xe00b
 #define PCI_DEVICE_ID_EICON_MAESTRA	0xe010
 #define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
 #define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
diff -urN linux-2.4.20-pre2/include/linux/serio.h linux-2.4.20-pre3/include/linux/serio.h
--- linux-2.4.20-pre2/include/linux/serio.h	Sun Aug 12 11:13:59 2001
+++ linux-2.4.20-pre3/include/linux/serio.h	Sat Aug 17 14:19:01 2002
@@ -87,6 +87,7 @@
 #define SERIO_XT	0x00000000UL
 #define SERIO_8042	0x01000000UL
 #define SERIO_RS232	0x02000000UL
+#define SERIO_HIL_MLC	0x03000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01
@@ -108,6 +109,7 @@
 #define SERIO_STOWAWAY	0x20
 #define SERIO_H3600	0x21
 #define SERIO_PS2SER	0x22
+#define SERIO_HIL	0x25
 
 #define SERIO_ID	0xff00UL
 #define SERIO_EXTRA	0xff0000UL
diff -urN linux-2.4.20-pre2/include/linux/smb_mount.h linux-2.4.20-pre3/include/linux/smb_mount.h
--- linux-2.4.20-pre2/include/linux/smb_mount.h	Fri Feb 16 16:03:24 2001
+++ linux-2.4.20-pre3/include/linux/smb_mount.h	Sat Aug 17 14:19:01 2002
@@ -50,8 +50,8 @@
 
 	u32 flags;
 
-        /* maximum age in jiffies (inode, dentry and dircache) */
-	int ttl;
+	int ttl;	/* maximum age in jiffies (inode, dentry & dircache) */
+	int timeo;	/* timeout for requests */
 
 	struct smb_nls_codepage codepage;
 };
diff -urN linux-2.4.20-pre2/include/linux/som.h linux-2.4.20-pre3/include/linux/som.h
--- linux-2.4.20-pre2/include/linux/som.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre3/include/linux/som.h	Sat Aug 17 14:19:01 2002
@@ -0,0 +1,154 @@
+#ifndef _LINUX_SOM_H
+#define _LINUX_SOM_H
+
+/* File format definition for SOM executables / shared libraries */
+
+/* we need struct timespec */
+#include <linux/time.h>
+
+#define SOM_PAGESIZE 4096
+
+/* this is the SOM header */
+struct som_hdr {
+	short		system_id;		/* magic number - system */
+	short		a_magic;		/* magic number - file type */
+	unsigned int	version_id;		/* versiod ID: YYMMDDHH */
+	struct timespec	file_time;		/* system clock */
+	unsigned int	entry_space;		/* space for entry point */
+	unsigned int	entry_subspace;		/* subspace for entry point */
+	unsigned int	entry_offset;		/* offset of entry point */
+	unsigned int	aux_header_location;	/* auxiliary header location */
+	unsigned int	aux_header_size;	/* auxiliary header size */
+	unsigned int	som_length;		/* length of entire SOM */
+	unsigned int	presumed_dp;		/* compiler's DP value */
+	unsigned int	space_location;		/* space dictionary location */
+	unsigned int	space_total;		/* number of space entries */
+	unsigned int	subspace_location;	/* subspace entries location */
+	unsigned int	subspace_total;		/* number of subspace entries */
+	unsigned int	loader_fixup_location;	/* MPE/iX loader fixup */
+	unsigned int	loader_fixup_total;	/* number of fixup records */
+	unsigned int	space_strings_location;	/* (sub)space names */
+	unsigned int	space_strings_size;	/* size of strings area */
+	unsigned int	init_array_location;	/* reserved */
+	unsigned int	init_array_total;	/* reserved */
+	unsigned int	compiler_location;	/* module dictionary */
+	unsigned int	compiler_total;		/* number of modules */
+	unsigned int	symbol_location;	/* symbol dictionary */
+	unsigned int	symbol_total;		/* number of symbols */
+	unsigned int	fixup_request_location;	/* fixup requests */
+	unsigned int	fixup_request_total;	/* number of fixup requests */
+	unsigned int	symbol_strings_location;/* module & symbol names area */
+	unsigned int	symbol_strings_size;	/* size of strings area */
+	unsigned int	unloadable_sp_location;	/* unloadable spaces location */
+	unsigned int	unloadable_sp_size;	/* size of data */
+	unsigned int	checksum;
+};
+
+/* values for system_id */
+
+#define SOM_SID_PARISC_1_0	0x020b
+#define SOM_SID_PARISC_1_1	0x0210
+#define SOM_SID_PARISC_2_0	0x0214
+
+/* values for a_magic */
+
+#define SOM_LIB_EXEC		0x0104
+#define SOM_RELOCATABLE		0x0106
+#define SOM_EXEC_NONSHARE	0x0107
+#define SOM_EXEC_SHARE		0x0108
+#define SOM_EXEC_DEMAND		0x010B
+#define SOM_LIB_DYN		0x010D
+#define SOM_LIB_SHARE		0x010E
+#define SOM_LIB_RELOC		0x0619
+
+/* values for version_id.  Decimal not hex, yes.  Grr. */
+
+#define SOM_ID_OLD		85082112
+#define SOM_ID_NEW		87102412
+
+struct aux_id {
+	unsigned int	mandatory :1;	/* the linker must understand this */
+	unsigned int	copy	  :1;	/* Must be copied by the linker */
+	unsigned int	append	  :1;	/* Must be merged by the linker */
+	unsigned int	ignore	  :1;	/* Discard section if unknown */
+	unsigned int	reserved  :12;
+	unsigned int	type	  :16;	/* Header type */
+	unsigned int	length;		/* length of _following_ data */
+};
+
+/* The Exec Auxiliary Header.  Called The HP-UX Header within HP apparently. */
+struct som_exec_auxhdr {
+	struct aux_id	som_auxhdr;
+	int		exec_tsize;	/* Text size in bytes */
+	int		exec_tmem;	/* Address to load text at */
+	int		exec_tfile;	/* Location of text in file */
+	int		exec_dsize;	/* Data size in bytes */
+	int		exec_dmem;	/* Address to load data at */
+	int		exec_dfile;	/* Location of data in file */
+	int		exec_bsize;	/* Uninitialised data (bss) */
+	int		exec_entry;	/* Address to start executing */
+	int		exec_flags;	/* loader flags */
+	int		exec_bfill;	/* initialisation value for bss */
+};
+
+/* Oh, the things people do to avoid casts.  Shame it'll break with gcc's
+ * new aliasing rules really.
+ */
+union name_pt {
+	char *		n_name;
+	unsigned int	n_strx;
+};
+
+/* The Space Dictionary */
+struct space_dictionary_record {
+	union name_pt	name;			/* index to subspace name */
+	unsigned int	is_loadable	:1;	/* loadable */
+	unsigned int	is_defined	:1;	/* defined within file */
+	unsigned int	is_private	:1;	/* not sharable */
+	unsigned int	has_intermediate_code :1; /* contains intermediate code */
+	unsigned int	is_tspecific	:1;	/* thread specific */
+	unsigned int	reserved	:11;	/* for future expansion */
+	unsigned int	sort_key	:8;	/* for linker */
+	unsigned int	reserved2	:8;	/* for future expansion */
+
+	int		space_number;		/* index */
+	int		subspace_index;		/* index into subspace dict */
+	unsigned int	subspace_quantity;	/* number of subspaces */
+	int		loader_fix_index;	/* for loader */
+	unsigned int	loader_fix_quantity;	/* for loader */
+	int		init_pointer_index;	/* data pointer array index */
+	unsigned int	init_pointer_quantity;	/* number of data pointers */
+};
+
+/* The Subspace Dictionary */
+struct subspace_dictionary_record {
+	int		space_index;
+	unsigned int	access_control_bits :7;
+	unsigned int	memory_resident	:1;
+	unsigned int	dup_common	:1;
+	unsigned int	is_common	:1;
+	unsigned int	quadrant	:2;
+	unsigned int	initially_frozen :1;
+	unsigned int	is_first	:1;
+	unsigned int	code_only	:1;
+	unsigned int	sort_key	:8;
+	unsigned int	replicate_init	:1;
+	unsigned int	continuation	:1;
+	unsigned int	is_tspecific	:1;
+	unsigned int	is_comdat	:1;
+	unsigned int	reserved	:4;
+
+	int		file_loc_init_value;
+	unsigned int	initialization_length;
+	unsigned int	subspace_start;
+	unsigned int	subspace_length;
+
+	unsigned int	reserved2	:5;
+	unsigned int	alignment	:27;
+
+	union name_pt	name;
+	int		fixup_request_index;
+	unsigned int	fixup_request_quantity;
+};
+
+#endif /* _LINUX_SOM_H */
diff -urN linux-2.4.20-pre2/include/linux/sonypi.h linux-2.4.20-pre3/include/linux/sonypi.h
--- linux-2.4.20-pre2/include/linux/sonypi.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.20-pre3/include/linux/sonypi.h	Sat Aug 17 14:19:01 2002
@@ -75,6 +75,7 @@
 #define SONYPI_EVENT_LID_OPENED			37
 #define SONYPI_EVENT_BLUETOOTH_ON		38
 #define SONYPI_EVENT_BLUETOOTH_OFF		39
+#define SONYPI_EVENT_HELP_PRESSED		40
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -urN linux-2.4.20-pre2/include/linux/sunrpc/sched.h linux-2.4.20-pre3/include/linux/sunrpc/sched.h
--- linux-2.4.20-pre2/include/linux/sunrpc/sched.h	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/include/linux/sunrpc/sched.h	Sat Aug 17 14:19:01 2002
@@ -75,9 +75,7 @@
 	wait_queue_head_t	tk_wait;	/* sync: sleep on this q */
 	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
 	unsigned short		tk_flags;	/* misc flags */
-	unsigned short		tk_lock;	/* Task lock counter */
-	unsigned char		tk_active   : 1,/* Task has been activated */
-				tk_wakeup   : 1;/* Task waiting to wake up */
+	unsigned char		tk_active   : 1;/* Task has been activated */
 	unsigned long		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
@@ -181,15 +179,11 @@
 void		rpc_remove_wait_queue(struct rpc_task *);
 void		rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
 					rpc_action action, rpc_action timer);
-void		rpc_sleep_locked(struct rpc_wait_queue *, struct rpc_task *,
-				 rpc_action action, rpc_action timer);
 void		rpc_add_timer(struct rpc_task *, rpc_action);
 void		rpc_wake_up_task(struct rpc_task *);
 void		rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
-int		__rpc_lock_task(struct rpc_task *);
-void		rpc_unlock_task(struct rpc_task *);
 void		rpc_delay(struct rpc_task *, unsigned long);
 void *		rpc_allocate(unsigned int flags, unsigned int);
 void		rpc_free(void *);
diff -urN linux-2.4.20-pre2/include/linux/sunrpc/xdr.h linux-2.4.20-pre3/include/linux/sunrpc/xdr.h
--- linux-2.4.20-pre2/include/linux/sunrpc/xdr.h	Thu Nov 22 11:47:20 2001
+++ linux-2.4.20-pre3/include/linux/sunrpc/xdr.h	Sat Aug 17 14:19:01 2002
@@ -34,6 +34,31 @@
 typedef int	(*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
 
 /*
+ * Basic structure for transmission/reception of a client XDR message.
+ * Features a header (for a linear buffer containing RPC headers
+ * and the data payload for short messages), and then an array of
+ * pages.
+ * The tail iovec allows you to append data after the page array. Its
+ * main interest is for appending padding to the pages in order to
+ * satisfy the int_32-alignment requirements in RFC1832.
+ *
+ * For the future, we might want to string several of these together
+ * in a list if anybody wants to make use of NFSv4 COMPOUND
+ * operations and/or has a need for scatter/gather involving pages.
+ */
+struct xdr_buf {
+	struct iovec	head[1],	/* RPC header + non-page data */
+			tail[1];	/* Appended after page data */
+
+	struct page **	pages;		/* Array of contiguous pages */
+	unsigned int	page_base,	/* Start of page data */
+			page_len;	/* Length of page data */
+
+	unsigned int	len;		/* Total length of data */
+
+};
+
+/*
  * pre-xdr'ed macros.
  */
 
@@ -67,6 +92,11 @@
 u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
 u32 *	xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len);
 
+void	xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
+			 unsigned int);
+void	xdr_inline_pages(struct xdr_buf *, unsigned int,
+			 struct page **, unsigned int, unsigned int);
+
 /*
  * Decode 64bit quantities (NFSv3 support)
  */
@@ -98,6 +128,40 @@
 void xdr_shift_iovec(struct iovec *, int, size_t);
 void xdr_zero_iovec(struct iovec *, int, size_t);
 
+/*
+ * Maximum number of iov's we use.
+ */
+#define MAX_IOVEC	(12)
+
+/*
+ * XDR buffer helper functions
+ */
+extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
+extern void xdr_kunmap(struct xdr_buf *, unsigned int);
+extern void xdr_shift_buf(struct xdr_buf *, unsigned int);
+extern void xdr_zero_buf(struct xdr_buf *, unsigned int);
+
+/*
+ * Helper structure for copying from an sk_buff.
+ */
+typedef struct {
+	struct sk_buff	*skb;
+	unsigned int	offset;
+	size_t		count;
+	unsigned int	csum;
+} skb_reader_t;
+
+typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);
+
+extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
+		skb_reader_t *, skb_read_actor_t);
+
+extern int xdr_copy_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset);
+
+extern int xdr_copy_and_csum_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset, unsigned int csum);
+
 #endif /* __KERNEL__ */
 
 #endif /* _SUNRPC_XDR_H_ */
diff -urN linux-2.4.20-pre2/include/linux/sunrpc/xprt.h linux-2.4.20-pre3/include/linux/sunrpc/xprt.h
--- linux-2.4.20-pre2/include/linux/sunrpc/xprt.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/include/linux/sunrpc/xprt.h	Sat Aug 17 14:19:01 2002
@@ -13,11 +13,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/sunrpc/sched.h>
-
-/*
- * Maximum number of iov's we use.
- */
-#define MAX_IOVEC	10
+#include <linux/sunrpc/xdr.h>
 
 /*
  * The transport code maintains an estimate on the maximum number of out-
@@ -70,15 +66,6 @@
 };
 
 /*
- * This is the RPC buffer
- */
-struct rpc_iov {
-	struct iovec		io_vec[MAX_IOVEC];
-	unsigned int		io_nr;
-	unsigned int		io_len;
-};
-
-/*
  * This describes a complete RPC request
  */
 struct rpc_rqst {
@@ -87,8 +74,8 @@
 	 */
 	struct rpc_xprt *	rq_xprt;		/* RPC client */
 	struct rpc_timeout	rq_timeout;		/* timeout parms */
-	struct rpc_iov		rq_snd_buf;		/* send buffer */
-	struct rpc_iov		rq_rcv_buf;		/* recv buffer */
+	struct xdr_buf		rq_snd_buf;		/* send buffer */
+	struct xdr_buf		rq_rcv_buf;		/* recv buffer */
 
 	/*
 	 * This is the private part
@@ -96,7 +83,9 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	volatile unsigned char	rq_received : 1;/* receive completed */
+	int			rq_received;	/* receive completed */
+
+	struct list_head	rq_list;
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -113,12 +102,10 @@
 	unsigned long		rq_xtime;	/* when transmitted */
 #endif
 };
-#define rq_svec			rq_snd_buf.io_vec
-#define rq_snr			rq_snd_buf.io_nr
-#define rq_slen			rq_snd_buf.io_len
-#define rq_rvec			rq_rcv_buf.io_vec
-#define rq_rnr			rq_rcv_buf.io_nr
-#define rq_rlen			rq_rcv_buf.io_len
+#define rq_svec			rq_snd_buf.head
+#define rq_slen			rq_snd_buf.len
+#define rq_rvec			rq_rcv_buf.head
+#define rq_rlen			rq_rcv_buf.len
 
 #define XPRT_LAST_FRAG		(1 << 0)
 #define XPRT_COPY_RECM		(1 << 1)
@@ -164,6 +151,8 @@
 	spinlock_t		xprt_lock;	/* lock xprt info */
 	struct rpc_task *	snd_task;	/* Task blocked in send */
 
+	struct list_head	recv;
+
 
 	void			(*old_data_ready)(struct sock *, int);
 	void			(*old_state_change)(struct sock *);
diff -urN linux-2.4.20-pre2/include/scsi/scsi.h linux-2.4.20-pre3/include/scsi/scsi.h
--- linux-2.4.20-pre2/include/scsi/scsi.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.20-pre3/include/scsi/scsi.h	Sat Aug 17 14:19:01 2002
@@ -89,6 +89,8 @@
 #define SEND_VOLUME_TAG       0xb6
 #define WRITE_LONG_2          0xea
 
+#define SCSI_RETRY_10(c) ((c) == READ_6 || (c) == WRITE_6 || (c) == SEEK_6)
+
 /*
  *  Status codes
  */
diff -urN linux-2.4.20-pre2/include/scsi/sg.h linux-2.4.20-pre3/include/scsi/sg.h
--- linux-2.4.20-pre2/include/scsi/sg.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/include/scsi/sg.h	Sat Aug 17 14:19:01 2002
@@ -11,9 +11,12 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.1.23 (20020318)
+    Version: 3.1.24 (20020505)
     This version is for 2.4 series kernels.
 
+    Changes since 3.1.23 (20020318)
+	- off by one fix for last scatter gather element
+	- zero buffer obtained for non-root users
     Changes since 3.1.22 (20011208)
 	- change EACCES to EPERM when O_RDONLY is insufficient
 	- suppress newlines in host string ( /proc/scsi/sg/host_strs output)
diff -urN linux-2.4.20-pre2/init/do_mounts.c linux-2.4.20-pre3/init/do_mounts.c
--- linux-2.4.20-pre2/init/do_mounts.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/init/do_mounts.c	Sat Aug 17 14:19:01 2002
@@ -776,10 +776,8 @@
 
 	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 	if (pid > 0) {
-		while (pid != wait(&i)) {
-			current->policy |= SCHED_YIELD;
-			schedule();
-		}
+		while (pid != wait(&i))
+			yield();
 	}
 
 	sys_mount("..", ".", NULL, MS_MOVE, NULL);
diff -urN linux-2.4.20-pre2/kernel/softirq.c linux-2.4.20-pre3/kernel/softirq.c
--- linux-2.4.20-pre2/kernel/softirq.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/kernel/softirq.c	Sat Aug 17 14:19:01 2002
@@ -260,8 +260,7 @@
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
 		current->state = TASK_RUNNING;
 		do {
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
 	}
 	tasklet_unlock_wait(t);
@@ -405,10 +404,8 @@
 				  CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
 			printk("spawn_ksoftirqd() failed for cpu %d\n", cpu);
 		else {
-			while (!ksoftirqd_task(cpu_logical_map(cpu))) {
-				current->policy |= SCHED_YIELD;
-				schedule();
-			}
+			while (!ksoftirqd_task(cpu_logical_map(cpu)))
+				yield();
 		}
 	}
 
diff -urN linux-2.4.20-pre2/lib/inflate.c linux-2.4.20-pre3/lib/inflate.c
--- linux-2.4.20-pre2/lib/inflate.c	Tue Mar  6 19:44:37 2001
+++ linux-2.4.20-pre3/lib/inflate.c	Sat Aug 17 14:19:01 2002
@@ -1009,7 +1009,7 @@
 
 static ulg crc_32_tab[256];
 static ulg crc;		/* initialized in makecrc() so it'll reside in bss */
-#define CRC_VALUE (crc ^ 0xffffffffL)
+#define CRC_VALUE (crc ^ 0xffffffffUL)
 
 /*
  * Code to compute the CRC-32 table. Borrowed from 
@@ -1049,7 +1049,7 @@
   }
 
   /* this is initialized here so this code could reside in ROM */
-  crc = (ulg)0xffffffffL; /* shift register contents */
+  crc = (ulg)0xffffffffUL; /* shift register contents */
 }
 
 /* gzip flag byte */
diff -urN linux-2.4.20-pre2/lib/rwsem-spinlock.c linux-2.4.20-pre3/lib/rwsem-spinlock.c
--- linux-2.4.20-pre2/lib/rwsem-spinlock.c	Wed Apr 25 13:31:03 2001
+++ linux-2.4.20-pre3/lib/rwsem-spinlock.c	Sat Aug 17 14:19:01 2002
@@ -4,6 +4,8 @@
  * Copyright (c) 2001   David Howells (dhowells@redhat.com).
  * - Derived partially from idea by Andrea Arcangeli <andrea@suse.de>
  * - Derived also from comments by Linus
+ *
+ * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  */
 #include <linux/rwsem.h>
 #include <linux/sched.h>
@@ -149,6 +151,28 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_read_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity>=0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity++;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_read_trylock");
+	return ret;
+}
+
+/*
  * get a write lock on the semaphore
  * - note that we increment the waiting count anyway to indicate an exclusive lock
  */
@@ -195,6 +219,28 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int ret = 0;
+	rwsemtrace(sem,"Entering __down_write_trylock");
+
+	spin_lock(&sem->wait_lock);
+
+	if (sem->activity==0 && list_empty(&sem->wait_list)) {
+		/* granted */
+		sem->activity = -1;
+		ret = 1;
+	}
+
+	spin_unlock(&sem->wait_lock);
+
+	rwsemtrace(sem,"Leaving __down_write_trylock");
+	return ret;
+}
+
+/*
  * release a read lock on the semaphore
  */
 void __up_read(struct rw_semaphore *sem)
diff -urN linux-2.4.20-pre2/mm/highmem.c linux-2.4.20-pre3/mm/highmem.c
--- linux-2.4.20-pre2/mm/highmem.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/mm/highmem.c	Sat Aug 17 14:19:01 2002
@@ -355,9 +355,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto repeat_alloc;
 }
 
@@ -393,9 +391,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto repeat_alloc;
 }
 
diff -urN linux-2.4.20-pre2/mm/oom_kill.c linux-2.4.20-pre3/mm/oom_kill.c
--- linux-2.4.20-pre2/mm/oom_kill.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/mm/oom_kill.c	Sat Aug 17 14:19:01 2002
@@ -188,8 +188,7 @@
 	 * killing itself before someone else gets the chance to ask
 	 * for more memory.
 	 */
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	return;
 }
 
diff -urN linux-2.4.20-pre2/mm/page_alloc.c linux-2.4.20-pre3/mm/page_alloc.c
--- linux-2.4.20-pre2/mm/page_alloc.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/mm/page_alloc.c	Sat Aug 17 14:19:01 2002
@@ -414,9 +414,7 @@
 		return NULL;
 
 	/* Yield for kswapd, and try again */
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 	goto rebalance;
 }
 
diff -urN linux-2.4.20-pre2/mm/swap.c linux-2.4.20-pre3/mm/swap.c
--- linux-2.4.20-pre2/mm/swap.c	Tue Nov  6 22:44:20 2001
+++ linux-2.4.20-pre3/mm/swap.c	Sat Aug 17 14:19:01 2002
@@ -57,9 +57,10 @@
  */
 void lru_cache_add(struct page * page)
 {
-	if (!TestSetPageLRU(page)) {
+	if (!PageLRU(page)) {
 		spin_lock(&pagemap_lru_lock);
-		add_page_to_inactive_list(page);
+		if (!TestSetPageLRU(page))
+			add_page_to_inactive_list(page);
 		spin_unlock(&pagemap_lru_lock);
 	}
 }
diff -urN linux-2.4.20-pre2/net/atm/proc.c linux-2.4.20-pre3/net/atm/proc.c
--- linux-2.4.20-pre2/net/atm/proc.c	Wed Jul  4 11:50:38 2001
+++ linux-2.4.20-pre3/net/atm/proc.c	Sat Aug 17 14:19:01 2002
@@ -551,9 +551,12 @@
 	digits = 0;
 	for (num = dev->number; num; num /= 10) digits++;
 	if (!digits) digits++;
-	dev->proc_name = kmalloc(strlen(dev->type)+digits+2,GFP_KERNEL);
-	if (!dev->proc_name) goto fail1;
+
+	dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
+	if (!dev->proc_name)
+		goto fail1;
 	sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
+
 	dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
 	if (!dev->proc_entry)
 		goto fail0;
diff -urN linux-2.4.20-pre2/net/atm/resources.c linux-2.4.20-pre3/net/atm/resources.c
--- linux-2.4.20-pre2/net/atm/resources.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/net/atm/resources.c	Sat Aug 17 14:19:01 2002
@@ -27,15 +27,14 @@
 struct atm_vcc *nodev_vccs = NULL;
 extern spinlock_t atm_dev_lock;
 
-/* Caller must hold atm_dev_lock. */
-static struct atm_dev *__alloc_atm_dev(const char *type)
+
+static struct atm_dev *alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
 
 	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
-	if (!dev)
-		return NULL;
-	memset(dev, 0, sizeof(*dev));
+	if (!dev) return NULL;
+	memset(dev,0,sizeof(*dev));
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
@@ -43,118 +42,100 @@
 
 	dev->prev = last_dev;
 
-	if (atm_devs)
-		last_dev->next = dev;
-	else
-		atm_devs = dev;
+	if (atm_devs) last_dev->next = dev;
+	else atm_devs = dev;
 	last_dev = dev;
-
 	return dev;
 }
 
-/* Caller must hold atm_dev_lock. */
-static void __free_atm_dev(struct atm_dev *dev)
-{
-	if (dev->prev)
-		dev->prev->next = dev->next;
-	else
-		atm_devs = dev->next;
-
-	if (dev->next)
-		dev->next->prev = dev->prev;
-	else
-		last_dev = dev->prev;
 
+static void free_atm_dev(struct atm_dev *dev)
+{
+	if (dev->prev) dev->prev->next = dev->next;
+	else atm_devs = dev->next;
+	if (dev->next) dev->next->prev = dev->prev;
+	else last_dev = dev->prev;
 	kfree(dev);
 }
 
-/* Caller must hold atm_dev_lock. */
 struct atm_dev *atm_find_dev(int number)
 {
 	struct atm_dev *dev;
 
 	for (dev = atm_devs; dev; dev = dev->next)
-		if (dev->ops && dev->number == number)
-			return dev;
+		if (dev->ops && dev->number == number) return dev;
 	return NULL;
 }
 
-struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
-				 int number, atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
+    int number,atm_dev_flags_t *flags)
 {
-	struct atm_dev *dev;
+	struct atm_dev *dev = NULL;
 
 	spin_lock(&atm_dev_lock);
 
-	dev = __alloc_atm_dev(type);
+	dev = alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
-		       type);
+		    type);
 		goto done;
 	}
 	if (number != -1) {
 		if (atm_find_dev(number)) {
-			__free_atm_dev(dev);
-			dev = NULL;
-			goto done;
+			free_atm_dev(dev);
+			return NULL;
 		}
 		dev->number = number;
 	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number))
-			dev->number++;
+		while (atm_find_dev(dev->number)) dev->number++;
 	}
 	dev->vccs = dev->last = NULL;
 	dev->dev_data = NULL;
 	barrier();
 	dev->ops = ops;
-	if (flags)
+	if (flags) 
 		dev->flags = *flags;
-	else
-		memset(&dev->flags, 0, sizeof(dev->flags));
-	memset(&dev->stats, 0, sizeof(dev->stats));
-
+	else 
+		memset(&dev->flags,0,sizeof(dev->flags));
+	memset((void *) &dev->stats,0,sizeof(dev->stats));
 #ifdef CONFIG_PROC_FS
-	if (ops->proc_read) {
+	if (ops->proc_read)
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
-			       "atm_proc_dev_register failed for dev %s\n",
-			       type);
-			__free_atm_dev(dev);
-			dev = NULL;
+			    "atm_proc_dev_register failed for dev %s\n",type);
+			free_atm_dev(dev);
 			goto done;
 		}
-	}
 #endif
 
 done:
-	spin_unlock(&atm_dev_lock);		
-
+	spin_unlock(&atm_dev_lock);
 	return dev;
 }
 
+
 void atm_dev_deregister(struct atm_dev *dev)
 {
 #ifdef CONFIG_PROC_FS
-	if (dev->ops->proc_read)
-		atm_proc_dev_deregister(dev);
+	if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
 #endif
 	spin_lock(&atm_dev_lock);
-	__free_atm_dev(dev);
+	free_atm_dev(dev);
 	spin_unlock(&atm_dev_lock);
 }
 
 void shutdown_atm_dev(struct atm_dev *dev)
 {
 	if (dev->vccs) {
-		set_bit(ATM_DF_CLOSE, &dev->flags);
+		set_bit(ATM_DF_CLOSE,&dev->flags);
 		return;
 	}
-	if (dev->ops->dev_close)
-		dev->ops->dev_close(dev);
+	if (dev->ops->dev_close) dev->ops->dev_close(dev);
 	atm_dev_deregister(dev);
 }
 
+
 /* Handler for sk->destruct, invoked by sk_free() */
 static void atm_free_sock(struct sock *sk)
 {
@@ -167,48 +148,44 @@
 	struct atm_vcc *vcc;
 
 	sk = sk_alloc(family, GFP_KERNEL, 1);
-	if (!sk)
-		return NULL;
+	if (!sk) return NULL;
 	vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
 	if (!vcc) {
 		sk_free(sk);
 		return NULL;
 	}
-	sock_init_data(NULL, sk);
+	sock_init_data(NULL,sk);
 	sk->destruct = atm_free_sock;
 	memset(vcc,0,sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs)
-		nodev_vccs->prev = vcc;
+	if (nodev_vccs) nodev_vccs->prev = vcc;
 	vcc->prev = NULL;
 	vcc->next = nodev_vccs;
 	nodev_vccs = vcc;
 	return sk;
 }
 
+
 static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
 {
-	if (vcc->prev)
-		vcc->prev->next = vcc->next;
-	else if (vcc->dev)
-		vcc->dev->vccs = vcc->next;
-	else
-		nodev_vccs = vcc->next;
-	if (vcc->next)
-		vcc->next->prev = vcc->prev;
-	else if (vcc->dev)
-		vcc->dev->last = vcc->prev;
+	if (vcc->prev) vcc->prev->next = vcc->next;
+	else if (vcc->dev) vcc->dev->vccs = vcc->next;
+	    else nodev_vccs = vcc->next;
+	if (vcc->next) vcc->next->prev = vcc->prev;
+	else if (vcc->dev) vcc->dev->last = vcc->prev;
 	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
 	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
 		shutdown_atm_dev(vcc->dev);
 }
 
+
 void free_atm_vcc_sk(struct sock *sk)
 {
-	unlink_vcc(sk->protinfo.af_atm, NULL);
+	unlink_vcc(sk->protinfo.af_atm,NULL);
 	sk_free(sk);
 }
 
+
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
 	unlink_vcc(vcc,dev);
@@ -216,20 +193,19 @@
 	if (dev) {
 		vcc->next = NULL;
 		vcc->prev = dev->last;
-		if (dev->vccs)
-			dev->last->next = vcc;
-		else
-			dev->vccs = vcc;
+		if (dev->vccs) dev->last->next = vcc;
+		else dev->vccs = vcc;
 		dev->last = vcc;
-	} else {
-		if (nodev_vccs)
-			nodev_vccs->prev = vcc;
+	}
+	else {
+		if (nodev_vccs) nodev_vccs->prev = vcc;
 		vcc->next = nodev_vccs;
 		vcc->prev = NULL;
 		nodev_vccs = vcc;
 	}
 }
 
+
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_find_dev);
diff -urN linux-2.4.20-pre2/net/core/pktgen.c linux-2.4.20-pre3/net/core/pktgen.c
--- linux-2.4.20-pre2/net/core/pktgen.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/core/pktgen.c	Sat Aug 17 14:19:01 2002
@@ -900,6 +900,7 @@
 		case ' ':
 			goto done_str;
 		default:
+			break;
 		};
 	}
 done_str:
diff -urN linux-2.4.20-pre2/net/ipv4/tcp_output.c linux-2.4.20-pre3/net/ipv4/tcp_output.c
--- linux-2.4.20-pre2/net/ipv4/tcp_output.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/net/ipv4/tcp_output.c	Sat Aug 17 14:19:01 2002
@@ -1010,8 +1010,7 @@
 			skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL);
 			if (skb)
 				break;
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		}
 
 		/* Reserve space for headers and prepare control bits. */
diff -urN linux-2.4.20-pre2/net/sched/sch_generic.c linux-2.4.20-pre3/net/sched/sch_generic.c
--- linux-2.4.20-pre2/net/sched/sch_generic.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre3/net/sched/sch_generic.c	Sat Aug 17 14:19:01 2002
@@ -475,10 +475,8 @@
 
 	dev_watchdog_down(dev);
 
-	while (test_bit(__LINK_STATE_SCHED, &dev->state)) {
-		current->policy |= SCHED_YIELD;
-		schedule();
-	}
+	while (test_bit(__LINK_STATE_SCHED, &dev->state))
+		yield();
 
 	spin_unlock_wait(&dev->xmit_lock);
 }
diff -urN linux-2.4.20-pre2/net/socket.c linux-2.4.20-pre3/net/socket.c
--- linux-2.4.20-pre2/net/socket.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/socket.c	Sat Aug 17 14:19:01 2002
@@ -147,8 +147,7 @@
 	while (atomic_read(&net_family_lockct) != 0) {
 		spin_unlock(&net_family_lock);
 
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 
 		spin_lock(&net_family_lock);
 	}
diff -urN linux-2.4.20-pre2/net/sunrpc/clnt.c linux-2.4.20-pre3/net/sunrpc/clnt.c
--- linux-2.4.20-pre2/net/sunrpc/clnt.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/sunrpc/clnt.c	Sat Aug 17 14:19:01 2002
@@ -461,6 +461,8 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	unsigned int	bufsiz;
 	kxdrproc_t	encode;
 	int		status;
@@ -473,14 +475,16 @@
 
 	/* Default buffer setup */
 	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
-	req->rq_svec[0].iov_base = (void *)task->tk_buffer;
-	req->rq_svec[0].iov_len  = bufsiz;
-	req->rq_slen		 = 0;
-	req->rq_snr		 = 1;
-	req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
-	req->rq_rvec[0].iov_len  = bufsiz;
-	req->rq_rlen		 = bufsiz;
-	req->rq_rnr		 = 1;
+	sndbuf->head[0].iov_base = (void *)task->tk_buffer;
+	sndbuf->head[0].iov_len  = bufsiz;
+	sndbuf->tail[0].iov_len  = 0;
+	sndbuf->page_len	 = 0;
+	sndbuf->len		 = 0;
+	rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
+	rcvbuf->head[0].iov_len  = bufsiz;
+	rcvbuf->tail[0].iov_len  = 0;
+	rcvbuf->page_len	 = 0;
+	rcvbuf->len		 = bufsiz;
 
 	/* Zero buffer so we have automatic zero-padding of opaque & string */
 	memset(task->tk_buffer, 0, bufsiz);
@@ -571,7 +575,7 @@
 	if (task->tk_status < 0)
 		return;
 	xprt_transmit(task);
-	if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc)) {
+	if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc) && task->tk_status >= 0) {
 		task->tk_action = NULL;
 		rpc_wake_up_task(task);
 	}
@@ -585,19 +589,22 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_xprt *xprt = clnt->cl_xprt;
-	struct rpc_rqst	*req;
-	int		status = task->tk_status;
+	struct rpc_rqst	*req = task->tk_rqstp;
+	int		status;
+
+	if (req->rq_received != 0)
+		task->tk_status = req->rq_received;
 
 	dprintk("RPC: %4d call_status (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
+	status = task->tk_status;
 	if (status >= 0) {
 		task->tk_action = call_decode;
 		return;
 	}
 
 	task->tk_status = 0;
-	req = task->tk_rqstp;
 	switch(status) {
 	case -ETIMEDOUT:
 		task->tk_action = call_timeout;
diff -urN linux-2.4.20-pre2/net/sunrpc/sched.c linux-2.4.20-pre3/net/sunrpc/sched.c
--- linux-2.4.20-pre2/net/sunrpc/sched.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/sunrpc/sched.c	Sat Aug 17 14:19:01 2002
@@ -73,7 +73,7 @@
  * Spinlock for wait queues. Access to the latter also has to be
  * interrupt-safe in order to allow timers to wake up sleeping tasks.
  */
-spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
 /*
  * Spinlock for other critical sections of code.
  */
@@ -157,7 +157,7 @@
 void rpc_add_timer(struct rpc_task *task, rpc_action timer)
 {
 	spin_lock_bh(&rpc_queue_lock);
-	if (!(RPC_IS_RUNNING(task) || task->tk_wakeup))
+	if (!RPC_IS_RUNNING(task))
 		__rpc_add_timer(task, timer);
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -358,27 +358,10 @@
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
-void
-rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task,
-		 rpc_action action, rpc_action timer)
-{
-	/*
-	 * Protect the queue operations.
-	 */
-	spin_lock_bh(&rpc_queue_lock);
-	__rpc_sleep_on(q, task, action, timer);
-	__rpc_lock_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
 /**
  * __rpc_wake_up_task - wake up a single rpc_task
  * @task: task to be woken up
  *
- * If the task is locked, it is merely removed from the queue, and
- * 'task->tk_wakeup' is set. rpc_unlock_task() will then ensure
- * that it is woken up as soon as the lock count goes to zero.
- *
  * Caller must hold rpc_queue_lock
  */
 static void
@@ -407,14 +390,6 @@
 	if (task->tk_rpcwait != &schedq)
 		__rpc_remove_wait_queue(task);
 
-	/* If the task has been locked, then set tk_wakeup so that
-	 * rpc_unlock_task() wakes us up... */
-	if (task->tk_lock) {
-		task->tk_wakeup = 1;
-		return;
-	} else
-		task->tk_wakeup = 0;
-
 	rpc_make_runnable(task);
 
 	dprintk("RPC:      __rpc_wake_up_task done\n");
@@ -502,30 +477,6 @@
 }
 
 /*
- * Lock down a sleeping task to prevent it from waking up
- * and disappearing from beneath us.
- *
- * This function should always be called with the
- * rpc_queue_lock held.
- */
-int
-__rpc_lock_task(struct rpc_task *task)
-{
-	if (!RPC_IS_RUNNING(task))
-		return ++task->tk_lock;
-	return 0;
-}
-
-void
-rpc_unlock_task(struct rpc_task *task)
-{
-	spin_lock_bh(&rpc_queue_lock);
-	if (task->tk_lock && !--task->tk_lock && task->tk_wakeup)
-		__rpc_wake_up_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
-/*
  * Run a task at a later time
  */
 static void	__rpc_atrun(struct rpc_task *);
@@ -707,15 +658,6 @@
 		spin_lock_bh(&rpc_queue_lock);
 
 		task_for_first(task, &schedq.tasks) {
-			if (task->tk_lock) {
-				spin_unlock_bh(&rpc_queue_lock);
-				printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
-#ifdef RPC_DEBUG			
-				rpc_debug = ~0;
-				rpc_show_tasks();
-#endif			
-				break;
-			}
 			__rpc_remove_wait_queue(task);
 			spin_unlock_bh(&rpc_queue_lock);
 
@@ -777,8 +719,7 @@
 		}
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 	} while (!signalled());
 
 	return NULL;
@@ -1104,8 +1045,7 @@
 		__rpc_schedule();
 		if (!list_empty(&all_tasks)) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
-			current->policy |= SCHED_YIELD;
-			schedule();
+			yield();
 		}
 	}
 
@@ -1175,8 +1115,7 @@
 	 * wait briefly before checking the process id.
 	 */
 	current->sigpending = 0;
-	current->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	/*
 	 * Display a message if we're going to wait longer.
 	 */
diff -urN linux-2.4.20-pre2/net/sunrpc/sunrpc_syms.c linux-2.4.20-pre3/net/sunrpc/sunrpc_syms.c
--- linux-2.4.20-pre2/net/sunrpc/sunrpc_syms.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/sunrpc/sunrpc_syms.c	Sat Aug 17 14:19:01 2002
@@ -96,8 +96,9 @@
 EXPORT_SYMBOL(xdr_decode_string_inplace);
 EXPORT_SYMBOL(xdr_decode_netobj);
 EXPORT_SYMBOL(xdr_encode_netobj);
-EXPORT_SYMBOL(xdr_shift_iovec);
-EXPORT_SYMBOL(xdr_zero_iovec);
+EXPORT_SYMBOL(xdr_encode_pages);
+EXPORT_SYMBOL(xdr_inline_pages);
+EXPORT_SYMBOL(xdr_shift_buf);
 
 /* Debugging symbols */
 #ifdef RPC_DEBUG
diff -urN linux-2.4.20-pre2/net/sunrpc/xdr.c linux-2.4.20-pre3/net/sunrpc/xdr.c
--- linux-2.4.20-pre2/net/sunrpc/xdr.c	Mon Oct  1 09:19:56 2001
+++ linux-2.4.20-pre3/net/sunrpc/xdr.c	Sat Aug 17 14:19:01 2002
@@ -10,6 +10,8 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
@@ -100,6 +102,46 @@
 }
 
 
+void
+xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
+		 unsigned int len)
+{
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	if (len & 3) {
+		struct iovec *iov = xdr->tail;
+		unsigned int pad = 4 - (len & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		len += pad;
+	}
+	xdr->len += len;
+}
+
+void
+xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
+		 struct page **pages, unsigned int base, unsigned int len)
+{
+	struct iovec *head = xdr->head;
+	struct iovec *tail = xdr->tail;
+	char *buf = (char *)head->iov_base;
+	unsigned int buflen = head->iov_len;
+
+	head->iov_len  = offset;
+
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	tail->iov_base = buf + offset;
+	tail->iov_len = buflen - offset;
+
+	xdr->len += len;
+}
+
 /*
  * Realign the iovec if the server missed out some reply elements
  * (such as post-op attributes,...)
@@ -132,19 +174,152 @@
 }
 
 /*
- * Zero the last n bytes in an iovec array of 'nr' elements
+ * Map a struct xdr_buf into an iovec array.
  */
-void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
 {
-	struct iovec *pvec;
+	struct iovec	*iov = iov_base;
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		iov->iov_len = len - base;
+		iov->iov_base = (char *)xdr->head[0].iov_base + base;
+		iov++;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto map_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto map_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		len = PAGE_CACHE_SIZE;
+		iov->iov_base = kmap(*ppage);
+		if (base) {
+			iov->iov_base += base;
+			len -= base;
+			base = 0;
+		}
+		if (pglen < len)
+			len = pglen;
+		iov->iov_len = len;
+		iov++;
+		ppage++;
+	} while ((pglen -= len) != 0);
+map_tail:
+	if (xdr->tail[0].iov_len) {
+		iov->iov_len = xdr->tail[0].iov_len - base;
+		iov->iov_base = (char *)xdr->tail[0].iov_base + base;
+		iov++;
+	}
+	return (iov - iov_base);
+}
 
-	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
-		if (n < pvec->iov_len) {
-			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
-			n = 0;
+void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	pglen = xdr->page_len;
+
+	if (!pglen)
+		return;
+	if (base > xdr->head[0].iov_len)
+		base -= xdr->head[0].iov_len;
+	else
+		base = 0;
+
+	if (base >= pglen)
+		return;
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+	}
+	for (;;) {
+		flush_dcache_page(*ppage);
+		kunmap(*ppage);
+		if (pglen <= PAGE_CACHE_SIZE)
+			break;
+		pglen -= PAGE_CACHE_SIZE;
+		ppage++;
+	}
+}
+
+void
+xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
+			  skb_reader_t *desc,
+			  skb_read_actor_t copy_actor)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+	int		ret;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		len -= base;
+		ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
+		if (ret != len || !desc->count)
+			return;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto copy_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto copy_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		char *kaddr;
+
+		len = PAGE_CACHE_SIZE;
+		kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
+		if (base) {
+			len -= base;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr + base, len);
+			base = 0;
 		} else {
-			memset(pvec->iov_base, 0, pvec->iov_len);
-			n -= pvec->iov_len;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr, len);
 		}
-	}
+		kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
+		if (ret != len || !desc->count)
+			return;
+		ppage++;
+	} while ((pglen -= len) != 0);
+copy_tail:
+	len = xdr->tail[0].iov_len;
+	if (len)
+		copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
+}
+
+void
+xdr_shift_buf(struct xdr_buf *xdr, size_t len)
+{
+	struct iovec iov[MAX_IOVEC];
+	unsigned int nr;
+
+	nr = xdr_kmap(iov, xdr, 0);
+	xdr_shift_iovec(iov, nr, len);
+	xdr_kunmap(xdr, 0);
 }
diff -urN linux-2.4.20-pre2/net/sunrpc/xprt.c linux-2.4.20-pre3/net/sunrpc/xprt.c
--- linux-2.4.20-pre2/net/sunrpc/xprt.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/sunrpc/xprt.c	Sat Aug 17 14:19:01 2002
@@ -67,8 +67,6 @@
 
 #include <asm/uaccess.h>
 
-extern spinlock_t rpc_queue_lock;
-
 /*
  * Local variables
  */
@@ -130,50 +128,13 @@
 }
 
 /*
- *	Adjust the iovec to move on 'n' bytes
- */
- 
-extern inline void
-xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
-{
-	struct iovec *iv=msg->msg_iov;
-	int i;
-	
-	/*
-	 *	Eat any sent iovecs
-	 */
-	while (iv->iov_len <= amount) {
-		amount -= iv->iov_len;
-		iv++;
-		msg->msg_iovlen--;
-	}
-
-	/*
-	 *	And chew down the partial one
-	 */
-	niv[0].iov_len = iv->iov_len-amount;
-	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
-	iv++;
-
-	/*
-	 *	And copy any others
-	 */
-	for(i = 1; i < msg->msg_iovlen; i++)
-		niv[i]=*iv++;
-
-	msg->msg_iov=niv;
-}
-
-/*
  * Serialize write access to sockets, in order to prevent different
  * requests from interfering with each other.
  * Also prevents TCP socket reconnections from colliding with writes.
  */
 static int
-xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
+__xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
-	int retval;
-	spin_lock_bh(&xprt->sock_lock);
 	if (!xprt->snd_task)
 		xprt->snd_task = task;
 	else if (xprt->snd_task != task) {
@@ -183,7 +144,15 @@
 		task->tk_status = -EAGAIN;
 		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 	}
-	retval = xprt->snd_task == task;
+	return xprt->snd_task == task;
+}
+
+static inline int
+xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	int retval;
+	spin_lock_bh(&xprt->sock_lock);
+	retval = __xprt_lock_write(xprt, task);
 	spin_unlock_bh(&xprt->sock_lock);
 	return retval;
 }
@@ -210,13 +179,11 @@
 {
 	struct socket	*sock = xprt->sock;
 	struct msghdr	msg;
+	struct xdr_buf	*xdr = &req->rq_snd_buf;
+	struct iovec	niv[MAX_IOVEC];
+	unsigned int	niov, slen, skip;
 	mm_segment_t	oldfs;
 	int		result;
-	int		slen = req->rq_slen - req->rq_bytes_sent;
-	struct iovec	niv[MAX_IOVEC];
-
-	if (slen <= 0)
-		return 0;
 
 	if (!sock)
 		return -ENOTCONN;
@@ -225,22 +192,25 @@
 				req->rq_svec->iov_base,
 				req->rq_svec->iov_len);
 
+	/* Dont repeat bytes */
+	skip = req->rq_bytes_sent;
+	slen = xdr->len - skip;
+	niov = xdr_kmap(niv, xdr, skip);
+
 	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
-	msg.msg_iov	= req->rq_svec;
-	msg.msg_iovlen	= req->rq_snr;
+	msg.msg_iov	= niv;
+	msg.msg_iovlen	= niov;
 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	/* Dont repeat bytes */
-	if (req->rq_bytes_sent)
-		xprt_move_iov(&msg, niv, req->rq_bytes_sent);
-
 	oldfs = get_fs(); set_fs(get_ds());
 	result = sock_sendmsg(sock, &msg, slen);
 	set_fs(oldfs);
 
+	xdr_kunmap(xdr, skip);
+
 	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
 
 	if (result >= 0)
@@ -460,7 +430,7 @@
 		if (inet->state != TCP_ESTABLISHED) {
 			task->tk_timeout = xprt->timeout.to_maxval;
 			/* if the socket is already closing, delay 5 secs */
-			if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
+			if ((1<<inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
 				task->tk_timeout = 5*HZ;
 			rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL);
 			release_sock(inet);
@@ -498,20 +468,16 @@
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
-	struct rpc_rqst	*req;
-	struct list_head *le;
-	struct rpc_task *task;
+	struct list_head *pos;
+	struct rpc_rqst	*req = NULL;
 
-	spin_lock_bh(&rpc_queue_lock);
-	task_for_each(task, le, &xprt->pending.tasks)
-		if ((req = task->tk_rqstp) && req->rq_xid == xid)
-			goto out;
-	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
-	req = NULL;
- out:
-	if (req && !__rpc_lock_task(req->rq_task))
-		req = NULL;
-	spin_unlock_bh(&rpc_queue_lock);
+	list_for_each(pos, &xprt->recv) {
+		struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
+		if (entry->rq_xid == xid) {
+			req = entry;
+			break;
+		}
+	}
 	return req;
 }
 
@@ -547,66 +513,68 @@
 #endif
 
 	dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
-	task->tk_status = copied;
-	req->rq_received = 1;
+	req->rq_received = copied;
+	list_del_init(&req->rq_list);
 
 	/* ... and wake up the process. */
 	rpc_wake_up_task(task);
 	return;
 }
 
+static size_t
+skb_read_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	if (len > desc->count)
+		len = desc->count;
+	skb_copy_bits(desc->skb, desc->offset, to, len);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
+static size_t
+skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	unsigned int csum2, pos;
+
+	if (len > desc->count)
+		len = desc->count;
+	pos = desc->offset;
+	csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0);
+	desc->csum = csum_block_add(desc->csum, csum2, pos);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
 /*
  * We have set things up such that we perform the checksum of the UDP
  * packet in parallel with the copies into the RPC client iovec.  -DaveM
  */
-static int csum_partial_copy_to_page_cache(struct iovec *iov,
-					   struct sk_buff *skb,
-					   int copied)
-{
-	int offset = sizeof(struct udphdr);
-	__u8 *cur_ptr = iov->iov_base;
-	__kernel_size_t cur_len = iov->iov_len;
-	unsigned int csum = skb->csum;
-	int need_csum = (skb->ip_summed != CHECKSUM_UNNECESSARY);
-	int slack = skb->len - copied - sizeof(struct udphdr);
-
-	if (need_csum)
-		csum = csum_partial(skb->data, sizeof(struct udphdr), csum);
-	while (copied > 0) {
-		if (cur_len) {
-			int to_move = cur_len;
-			if (to_move > copied)
-				to_move = copied;
-			if (need_csum) {
-				unsigned int csum2;
-
-				csum2 = skb_copy_and_csum_bits(skb, offset,
-							       cur_ptr,
-							       to_move, 0);
-				csum = csum_block_add(csum, csum2, offset);
-			} else
-				skb_copy_bits(skb, offset, cur_ptr, to_move);
-			offset += to_move;
-			copied -= to_move;
-			cur_ptr += to_move;
-			cur_len -= to_move;
-		}
-		if (cur_len <= 0) {
-			iov++;
-			cur_len = iov->iov_len;
-			cur_ptr = iov->iov_base;
-		}
-	}
-	if (need_csum) {
-		if (slack > 0) {
-			unsigned int csum2;
+static int
+csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
+{
+	skb_reader_t desc;
 
-			csum2 = skb_checksum(skb, offset, slack, 0);
-			csum = csum_block_add(csum, csum2, offset);
-		}
-		if ((unsigned short)csum_fold(csum))
-			return -1;
+	desc.skb = skb;
+	desc.offset = sizeof(struct udphdr);
+	desc.count = skb->len - desc.offset;
+
+	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+		goto no_checksum;
+
+	desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits);
+	if (desc.offset != skb->len) {
+		unsigned int csum2;
+		csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
+		desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
 	}
+	if ((unsigned short)csum_fold(desc.csum))
+		return -1;
+	return 0;
+no_checksum:
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits);
 	return 0;
 }
 
@@ -644,9 +612,10 @@
 	}
 
 	/* Look up and lock the request corresponding to the given XID */
+	spin_lock(&xprt->sock_lock);
 	rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
 	if (!rovr)
-		goto dropit;
+		goto out_unlock;
 	task = rovr->rq_task;
 
 	dprintk("RPC: %4d received reply\n", task->tk_pid);
@@ -657,7 +626,7 @@
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
-	if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied))
+	if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb))
 		goto out_unlock;
 
 	/* Something worked... */
@@ -666,8 +635,7 @@
 	xprt_complete_rqst(xprt, rovr, copied);
 
  out_unlock:
-	rpc_unlock_task(task);
-
+	spin_unlock(&xprt->sock_lock);
  dropit:
 	skb_free_datagram(sk, skb);
  out:
@@ -675,12 +643,6 @@
 		wake_up_interruptible(sk->sleep);
 }
 
-typedef struct {
-	struct sk_buff *skb;
-	unsigned offset;
-	size_t count;
-} skb_reader_t;
-
 /*
  * Copy from an skb into memory and shrink the skb.
  */
@@ -771,50 +733,43 @@
 tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
 {
 	struct rpc_rqst *req;
-	struct iovec *iov;
-	char *p;
-	unsigned long skip;
-	size_t len, used;
-	int n;
+	struct xdr_buf *rcvbuf;
+	size_t len;
 
 	/* Find and lock the request corresponding to this xid */
+	spin_lock(&xprt->sock_lock);
 	req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
 	if (!req) {
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 		dprintk("RPC:      XID %08x request not found!\n",
 				xprt->tcp_xid);
+		spin_unlock(&xprt->sock_lock);
 		return;
 	}
-	skip = xprt->tcp_copied;
-	iov = req->rq_rvec;
-	for (n = req->rq_rnr; n != 0; n--, iov++) {
-		if (skip >= iov->iov_len) {
-			skip -= iov->iov_len;
-			continue;
-		}
-		p = iov->iov_base;
-		len = iov->iov_len;
-		if (skip) {
-			p += skip;
-			len -= skip;
-			skip = 0;
-		}
-		if (xprt->tcp_offset + len > xprt->tcp_reclen)
-			len = xprt->tcp_reclen - xprt->tcp_offset;
-		used = tcp_copy_data(desc, p, len);
-		xprt->tcp_copied += used;
-		xprt->tcp_offset += used;
-		if (used != len)
-			break;
-		if (xprt->tcp_copied == req->rq_rlen) {
+
+	rcvbuf = &req->rq_rcv_buf;
+	len = desc->count;
+	if (len > xprt->tcp_reclen - xprt->tcp_offset) {
+		skb_reader_t my_desc;
+
+		len = xprt->tcp_reclen - xprt->tcp_offset;
+		memcpy(&my_desc, desc, sizeof(my_desc));
+		my_desc.count = len;
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  &my_desc, tcp_copy_data);
+		desc->count -= len;
+		desc->offset += len;
+	} else
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  desc, tcp_copy_data);
+	xprt->tcp_copied += len;
+	xprt->tcp_offset += len;
+
+	if (xprt->tcp_copied == req->rq_rlen)
+		xprt->tcp_flags &= ~XPRT_COPY_DATA;
+	else if (xprt->tcp_offset == xprt->tcp_reclen) {
+		if (xprt->tcp_flags & XPRT_LAST_FRAG)
 			xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
-		if (xprt->tcp_offset == xprt->tcp_reclen) {
-			if (xprt->tcp_flags & XPRT_LAST_FRAG)
-				xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
 	}
 
 	if (!(xprt->tcp_flags & XPRT_COPY_DATA)) {
@@ -822,7 +777,7 @@
 				req->rq_task->tk_pid);
 		xprt_complete_rqst(xprt, req, xprt->tcp_copied);
 	}
-	rpc_unlock_task(req->rq_task); 
+	spin_unlock(&xprt->sock_lock);
 	tcp_check_recm(xprt);
 }
 
@@ -979,16 +934,21 @@
 xprt_timer(struct rpc_task *task)
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct rpc_xprt *xprt = req->rq_xprt;
 
-	if (req)
-		xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT);
+	spin_lock(&xprt->sock_lock);
+	if (req->rq_received)
+		goto out;
+	xprt_adjust_cwnd(xprt, -ETIMEDOUT);
 
 	dprintk("RPC: %4d xprt_timer (%s request)\n",
 		task->tk_pid, req ? "pending" : "backlogged");
 
 	task->tk_status  = -ETIMEDOUT;
+out:
 	task->tk_timeout = 0;
 	rpc_wake_up_task(task);
+	spin_unlock(&xprt->sock_lock);
 }
 
 /*
@@ -1024,8 +984,16 @@
 		*marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker)));
 	}
 
-	if (!xprt_lock_write(xprt, task))
+	spin_lock_bh(&xprt->sock_lock);
+	if (!__xprt_lock_write(xprt, task)) {
+		spin_unlock_bh(&xprt->sock_lock);
 		return;
+	}
+	if (list_empty(&req->rq_list)) {
+		list_add_tail(&req->rq_list, &xprt->recv);
+		req->rq_received = 0;
+	}
+	spin_unlock_bh(&xprt->sock_lock);
 
 #ifdef RPC_PROFILE
 	req->rq_xtime = jiffies;
@@ -1041,14 +1009,6 @@
 	int status, retry = 0;
 
 
-	/* For fast networks/servers we have to put the request on
-	 * the pending list now:
-	 * Note that we don't want the task timing out during the
-	 * call to xprt_sendmsg(), so we initially disable the timeout,
-	 * and then reset it later...
-	 */
-	xprt_receive(task);
-
 	/* Continue transmitting the packet/record. We must be careful
 	 * to cope with writespace callbacks arriving _after_ we have
 	 * called xprt_sendmsg().
@@ -1080,15 +1040,11 @@
 		if (retry++ > 50)
 			break;
 	}
-	rpc_unlock_task(task);
 
 	/* Note: at this point, task->tk_sleeping has not yet been set,
 	 *	 hence there is no danger of the waking up task being put on
 	 *	 schedq, and being picked up by a parallel run of rpciod().
 	 */
-	rpc_wake_up_task(task);
-	if (!RPC_IS_RUNNING(task))
-		goto out_release;
 	if (req->rq_received)
 		goto out_release;
 
@@ -1123,31 +1079,15 @@
 	dprintk("RPC: %4d xmit complete\n", task->tk_pid);
 	/* Set the task's receive timeout value */
 	task->tk_timeout = req->rq_timeout.to_current;
-	rpc_add_timer(task, xprt_timer);
-	rpc_unlock_task(task);
+	spin_lock_bh(&xprt->sock_lock);
+	if (!req->rq_received)
+		rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
+	spin_unlock_bh(&xprt->sock_lock);
  out_release:
 	xprt_release_write(xprt, task);
 }
 
 /*
- * Queue the task for a reply to our call.
- * When the callback is invoked, the congestion window should have
- * been updated already.
- */
-void
-xprt_receive(struct rpc_task *task)
-{
-	struct rpc_rqst	*req = task->tk_rqstp;
-	struct rpc_xprt	*xprt = req->rq_xprt;
-
-	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
-
-	req->rq_received = 0;
-	task->tk_timeout = 0;
-	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
-}
-
-/*
  * Reserve an RPC call slot.
  */
 int
@@ -1234,6 +1174,7 @@
 	req->rq_xid     = xid++;
 	if (!xid)
 		xid++;
+	INIT_LIST_HEAD(&req->rq_list);
 }
 
 /*
@@ -1252,6 +1193,10 @@
 	}
 	if (!(req = task->tk_rqstp))
 		return;
+	spin_lock_bh(&xprt->sock_lock);
+	if (!list_empty(&req->rq_list))
+		list_del(&req->rq_list);
+	spin_unlock_bh(&xprt->sock_lock);
 	task->tk_rqstp = NULL;
 	memset(req, 0, sizeof(*req));	/* mark unused */
 
@@ -1326,6 +1271,8 @@
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
+	INIT_LIST_HEAD(&xprt->recv);
+
 	/* Set timeout parameters */
 	if (to) {
 		xprt->timeout = *to;
diff -urN linux-2.4.20-pre2/net/unix/af_unix.c linux-2.4.20-pre3/net/unix/af_unix.c
--- linux-2.4.20-pre2/net/unix/af_unix.c	Sat Aug 17 14:18:28 2002
+++ linux-2.4.20-pre3/net/unix/af_unix.c	Sat Aug 17 14:19:01 2002
@@ -565,10 +565,8 @@
 				      addr->hash)) {
 		write_unlock(&unix_table_lock);
 		/* Sanity yield. It is unusual case, but yet... */
-		if (!(ordernum&0xFF)) {
-			current->policy |= SCHED_YIELD;
-			schedule();
-		}
+		if (!(ordernum&0xFF))
+			yield();
 		goto retry;
 	}
 	addr->hash ^= sk->type;
