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

diff -urN linux-2.4.21-pre1/CREDITS linux-2.4.21-pre2/CREDITS
--- linux-2.4.21-pre1/CREDITS	Wed Dec 18 14:16:23 2002
+++ linux-2.4.21-pre2/CREDITS	Wed Dec 18 14:16:26 2002
@@ -733,7 +733,7 @@
 D: Dell PowerEdge server, SCSI layer, misc drivers, and other patches
 S: Dell Computer Corporation
 S: One Dell Way
-S: Round Rock, TX  78681
+S: Round Rock, TX  78682
 S: USA
 
 N: Eddie C. Dost
@@ -1065,6 +1065,11 @@
 D: Transformed old user space bdflush into 1st kernel thread - kflushd.
 D: Many other patches, documentation files, mini kernels, utilities, ...
 
+N: Masanori GOTO
+E: gotom@debian.or.jp
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: John E. Gotts
 E: jgotts@linuxsavvy.com
 D: kernel hacker
@@ -1231,11 +1236,13 @@
 
 N: Christoph Hellwig
 E: hch@infradead.org
-D: misc driver & makefile hacking
+E: hch@sgi.com
+D: all kinds of driver, filesystem & core kernel hacking
 D: freevxfs driver
 D: sysvfs maintainer
-S: Triftstraße 26
-S: 38644 Goslar
+D: chief codingstyle nitpicker
+S: Auweg 38
+S: 85748 Garching
 S: Germany
 
 N: Richard Henderson
@@ -3282,6 +3289,12 @@
 S: Socorro NM, 87801
 S: USA
 
+N: Hiroshi YOKOTA
+E: yokota@netlab.is.tsukuba.ac.jp
+D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: Eric Youngdale
 E: eric@andante.org
 W: http://www.andante.org
diff -urN linux-2.4.21-pre1/Documentation/Configure.help linux-2.4.21-pre2/Documentation/Configure.help
--- linux-2.4.21-pre1/Documentation/Configure.help	Wed Dec 18 14:16:23 2002
+++ linux-2.4.21-pre2/Documentation/Configure.help	Wed Dec 18 14:16:26 2002
@@ -1122,10 +1122,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X and CMD680 chipset support
+CMD64X/CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
+  chipsets: CMD643, CMD646 and CMD648.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1284,6 +1284,11 @@
 
   Please read the comments at the top of <file:drivers/ide/sis5513.c>.
 
+Silicon Image chipset support
+CONFIG_BLK_DEV_SIIMAGE
+  This driver provides (U)DMA support for the SII3112 SATA controllers and
+  for the CMD/SI680 UDMA/DMA ATA controller.
+
 SLC90E66 chipset support
 CONFIG_BLK_DEV_SLC90E66
   This driver ensures (U)DMA support for Victroy66 SouthBridges for
@@ -4431,7 +4436,7 @@
 
   The driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want). The
-  module will be called rivafb.o. If you want to compile it as a
+  module will be called tridentfb.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 ATI Mach64 display support
@@ -7922,6 +7927,17 @@
 
   The common answer here is N, but answering Y is safe.
 
+Workbit NinjaSCSI-32Bi/UDE support
+CONFIG_SCSI_NSP32
+  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called nsp32.o.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   This is support for the IBM SCSI adapter found in many of the PS/2
@@ -14184,6 +14200,17 @@
   The module will be called pl2303.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB KOBIL chipcard reader
+CONFIG_USB_SERIAL_KOBIL_SCT
+  Say Y here if you want to use one of the following KOBIL USB chipcard 
+  readers: TWIN, KAAN Standard Plus, SecOVID Reader Plus, B1 PRO, KAAN PRO
+
+  Note that you need a current CT-API.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kobil_sct.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB REINER SCT cyberJack pinpad/e-com chipcard reader
 CONFIG_USB_SERIAL_CYBERJACK
   Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
@@ -14688,6 +14715,28 @@
 
   If unsure, say N.
 
+Texas Instruments parallel link cable support
+CONFIG_TIPAR
+  If you own a Texas Instruments graphing calculator and use a
+  parallel link cable, then you might be interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev. The
+  main advantage of this driver is that you don't have to be root
+  to use this precise link cable (depending on the permissions on
+  the device nodes, though).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tipar.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>
+
+  If you don't know what a parallel link cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
   Say Y here if you want to use the Voyager USB Braille display from
@@ -15227,6 +15276,35 @@
   debugging output from the driver. This is unlike previous versions
   of the driver, where enabling this option would turn on debugging
   output automatically.
+  
+  Example:
+  mount -t befs /dev/hda2 /mnt -o debug
+
+BeOS filesystem support (BeFS) (read only)
+CONFIG_BEFS_FS
+  The BeOS File System (BeFS) is the native file system of Be, Inc's
+  BeOS. Notable features include support for arbitrary attributes
+  on files and directories, and database-like indices on selected
+  attributes. (Also note that this driver doesn't make those features
+  available at this time). It is a 64 bit filesystem, so it supports
+  extremely large volumes and files.
+
+  If you use this filesystem, you should also say Y to at least one
+  of the NLS (native language support) options below.
+
+  If you don't know what this is about, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called befs.o.
+
+Debug BeFS
+CONFIG_BEFS_DEBUG
+  If you say Y here, you can use the 'debug' mount option to enable
+  debugging output from the driver. This is unlike previous versions
+  of the driver, where enabling this option would turn on debugging
+  output automatically.
 
   Example:
   mount -t befs /dev/hda2 /mnt -o debug
@@ -19091,10 +19169,11 @@
   The module will be called cs461x.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aureal Vortex and Trident 4DWave gameports
+Aureal Vortex, Trident 4DWave, and ALi 5451 gameports
 CONFIG_INPUT_PCIGAME
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
+  card or an ALi 5451 chip on your motherboard. For more information
+  on how to use the driver please read
   <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
@@ -26272,7 +26351,7 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.  The module
-  will be called amdtp.o.
+  will be called cmp.o.
 
 OHCI-DV I/O support
 CONFIG_IEEE1394_DV1394
diff -urN linux-2.4.21-pre1/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.21-pre2/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.21-pre1/Documentation/DocBook/kernel-hacking.tmpl	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre2/Documentation/DocBook/kernel-hacking.tmpl	Wed Dec 18 14:16:26 2002
@@ -1139,11 +1139,6 @@
     </listitem>
     <listitem>
      <para>
-      Labeled elements
-     </para>
-    </listitem>
-    <listitem>
-     <para>
       typeof
      </para>
     </listitem>
diff -urN linux-2.4.21-pre1/Documentation/DocBook/kernel-locking.tmpl linux-2.4.21-pre2/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.21-pre1/Documentation/DocBook/kernel-locking.tmpl	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/Documentation/DocBook/kernel-locking.tmpl	Wed Dec 18 14:16:26 2002
@@ -1055,10 +1055,8 @@
       Another common problem is deleting timers which restart
       themselves (by calling <function>add_timer()</function> at the end 
       of their timer function).  Because this is a fairly common case 
-      which is prone to races, you can put a call to
-      <function>timer_exit()</function> at the very end of your timer function,
-      and user <function>del_timer_sync()</function> 
-      (<filename class=headerfile>include/linux/timer.h</filename>)
+      which is prone to races, you should use <function>del_timer_sync()</function> 
+      (<filename class=headerfile>include/linux/timer.h</filename>) 
       to handle this case.  It returns the number of times the timer 
       had to be deleted before we finally stopped it from adding itself back 
       in.
diff -urN linux-2.4.21-pre1/Documentation/cciss.txt linux-2.4.21-pre2/Documentation/cciss.txt
--- linux-2.4.21-pre1/Documentation/cciss.txt	Wed Dec 18 14:16:23 2002
+++ linux-2.4.21-pre2/Documentation/cciss.txt	Wed Dec 18 14:16:26 2002
@@ -89,7 +89,7 @@
 
 Hot plugging of SCSI tape drives is supported, with some caveats.
 The cciss driver must be informed that changes to the SCSI bus
-have been made, in addition to and prior to informing the the SCSI 
+have been made, in addition to and prior to informing the SCSI 
 mid layer.  This may be done via the /proc filesystem.  For example:
 
 	echo "rescan" > /proc/scsi/cciss0/1
diff -urN linux-2.4.21-pre1/Documentation/filesystems/Locking linux-2.4.21-pre2/Documentation/filesystems/Locking
--- linux-2.4.21-pre1/Documentation/filesystems/Locking	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre2/Documentation/filesystems/Locking	Wed Dec 18 14:16:26 2002
@@ -93,6 +93,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
@@ -108,6 +109,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	yes	yes	maybe		(see below)
+write_super:	yes	no	maybe		(see below)
 statfs:		yes	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
diff -urN linux-2.4.21-pre1/Documentation/networking/bonding.txt linux-2.4.21-pre2/Documentation/networking/bonding.txt
--- linux-2.4.21-pre1/Documentation/networking/bonding.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/Documentation/networking/bonding.txt	Wed Dec 18 14:16:26 2002
@@ -266,7 +266,7 @@
 	If not explicitly configured with ifconfig, the MAC address of the
 	bonding device is taken from its first slave device. This MAC address
 	is then passed to all following slaves and remains persistent (even if
-	the the first slave is removed) until the bonding device is brought
+	the first slave is removed) until the bonding device is brought
 	down or reconfigured.
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
diff -urN linux-2.4.21-pre1/Documentation/networking/pktgen.txt linux-2.4.21-pre2/Documentation/networking/pktgen.txt
--- linux-2.4.21-pre1/Documentation/networking/pktgen.txt	Thu Nov 28 15:53:08 2002
+++ linux-2.4.21-pre2/Documentation/networking/pktgen.txt	Wed Dec 18 14:16:26 2002
@@ -6,7 +6,7 @@
 3. Edit script to set preferred device and destination IP address.
 3a.  Create more scripts for different interfaces.  Up to thirty-two
      pktgen processes can be configured and run at once by using the
-     32 /proc/net/pg* files.
+     32 /proc/net/pktgen/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -52,7 +52,7 @@
 
 modprobe pktgen
 
-PGDEV=/proc/net/pg/pg0
+PGDEV=/proc/net/pktgen/pg0
 
 function pgset() {
     local result
diff -urN linux-2.4.21-pre1/Documentation/tipar.txt linux-2.4.21-pre2/Documentation/tipar.txt
--- linux-2.4.21-pre1/Documentation/tipar.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/Documentation/tipar.txt	Wed Dec 18 14:16:26 2002
@@ -0,0 +1,93 @@
+
+		Parallel link cable for Texas Instruments handhelds
+		===================================================
+
+
+Author: Romain Lievin
+Homepage: http://lpg.ticalc.org/prj_tidev
+
+
+INTRODUCTION:
+
+This is a driver for the very common home-made parallel link cable, a cable 
+designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
+or workstation (Alpha, Sparc). Given that driver is built on parport, the 
+parallel port abstraction layer, this driver is independant of the platform.
+
+It can also be used with another device plugged on the same port (such as a
+ZIP drive). I have a 100MB ZIP and both of them work fine !
+
+If you need more information, please visit the 'TI drivers' homepage at the URL
+above.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tipar (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled parport support (CONFIG_PARPORT_DEV): either 
+compiled in your kernel, either as a module. 
+This driver supports the new device hierarchy (devfs).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       modprobe parport
+       insmod tipar.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tipar0 c 115 0
+       mknod /dev/tipar1 c 115 1
+       mknod /dev/tipar2 c 115 2
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tipar?
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tipar NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+	time has expired then the driver will return with a timeout error.
+
+  NAME: delay
+  TYPE: integer
+  DEFAULT: 10
+  DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data 
+	rate but makes transmission less reliable.
+
+These parameters can be changed at run time by any program via ioctl(2) calls 
+as listed in ./include/linux/ticable.h
+Rather than write 50 pages describing the ioctl() and so on, it is
+perhaps more useful you look at ticables library (dev_link.c) that demonstrates
+how to use them, and demonstrates the features of the driver. This is
+probably a lot more useful to people interested in writing applications
+that will be using this driver.
+
+QUIRKS/BUGS:
+
+None.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIPAR: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org. He packaged these drivers for Debian.
+
+CREDITS:
+
+The code is based on tidev.c & parport.c.
+The driver has been developed independantly of Texas Instruments.
diff -urN linux-2.4.21-pre1/Documentation/watchdog-api.txt linux-2.4.21-pre2/Documentation/watchdog-api.txt
--- linux-2.4.21-pre1/Documentation/watchdog-api.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/Documentation/watchdog-api.txt	Wed Dec 18 14:16:26 2002
@@ -278,7 +278,7 @@
 	when the timeout runs out which can be 0 = RESET (default), 
 	1 = SMI, 2 = NMI, 3 = SCI.
 
-	Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+	Supports CONFIG_WATCHDOG_NOWAYOUT and the magic character
 	'V' close handling.
 
 	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
diff -urN linux-2.4.21-pre1/MAINTAINERS linux-2.4.21-pre2/MAINTAINERS
--- linux-2.4.21-pre1/MAINTAINERS	Wed Dec 18 14:16:23 2002
+++ linux-2.4.21-pre2/MAINTAINERS	Wed Dec 18 14:16:26 2002
@@ -154,6 +154,14 @@
 W:	http://www.ibm.com/linux/ltc/
 S:	Supported
 
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-announce@dell.com
+W:	http://domsch.com/linux
+S:	Supported
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -245,7 +253,7 @@
 BEFS FILE SYSTEM
 P:	Will Dyson
 M:	will@cs.earlham.edu
-W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+W:	http://befs-driver.sourceforge.net/
 S:	Maintained
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
@@ -286,13 +294,6 @@
 W:	http://bytesex.org/bttv/
 S:	Maintained
 
-BUSLOGIC SCSI DRIVER
-P:	Leonard N. Zubkoff
-M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.dandelion.com/Linux/
-S:	Maintained
-
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
@@ -1041,6 +1042,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/meye/
+S:	Maintained
+
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -1145,6 +1152,14 @@
 W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:	Maintained
 
+NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
+P:	GOTO Masanori
+M:	gotom@debian.or.jp
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1277,6 +1292,13 @@
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
+PHILIPS NINO PALM PC
+P:	Steven Hill
+M:	sjhill@realitydiluted.com
+L:	linux-mips@oss.sgi.com
+W:	http://www.realitydiluted.com/projects/nino
+S:	Maintained
+
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
@@ -1316,17 +1338,6 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
-PROMISE PDC202XX IDE CONTROLLER DRIVER
-P:	Hank Yang
-M:	support@promise.com.tw [TAIWAN]
-P:	Jordan Rhody
-M:	support@promise.com [U.S.A]
-P:	Jack Hu
-M:	support-china@promise.com [CHINA]
-W:	http://www.promise.com/support/linux_eng.asp
-W:	http://www.promise.com.tw/support/linux_eng.asp
-S:	Maintained
-
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -1439,6 +1450,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+SCx200 CPU SUPPORT
+P:	Christer Weinigel
+M:	christer@weinigel.se
+W:	http://www.weinigel.se
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
@@ -1487,6 +1504,12 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+SONY VAIO CONTROL DEVICE DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/sonypi/
+S:	Maintained
+
 SOUND
 P:	Alan Cox
 M:	alan@redhat.com
@@ -1584,6 +1607,11 @@
 M:      jb@technologeek.org
 S:      Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
diff -urN linux-2.4.21-pre1/Makefile linux-2.4.21-pre2/Makefile
--- linux-2.4.21-pre1/Makefile	Wed Dec 18 14:16:23 2002
+++ linux-2.4.21-pre2/Makefile	Wed Dec 18 14:16:26 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -pre1
+EXTRAVERSION = -pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.21-pre1/arch/arm/config.in linux-2.4.21-pre2/arch/arm/config.in
--- linux-2.4.21-pre1/arch/arm/config.in	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/arm/config.in	Wed Dec 18 14:16:26 2002
@@ -83,7 +83,7 @@
    choice 'Cerf Flash available'  \
         "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
          16MB   CONFIG_SA1100_CERF_FLASH_16MB \
-         32MB   CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash
+         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
    bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
 fi
 dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
diff -urN linux-2.4.21-pre1/arch/cris/boot/compressed/decompress.ld linux-2.4.21-pre2/arch/cris/boot/compressed/decompress.ld
--- linux-2.4.21-pre1/arch/cris/boot/compressed/decompress.ld	Thu Jul 26 15:10:06 2001
+++ linux-2.4.21-pre2/arch/cris/boot/compressed/decompress.ld	Wed Dec 18 14:16:26 2002
@@ -13,6 +13,7 @@
 		_stext = . ;
 		*(.text)
 		*(.rodata)
+		*(.rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
diff -urN linux-2.4.21-pre1/arch/cris/boot/rescue/Makefile linux-2.4.21-pre2/arch/cris/boot/rescue/Makefile
--- linux-2.4.21-pre1/arch/cris/boot/rescue/Makefile	Mon Feb 25 11:37:52 2002
+++ linux-2.4.21-pre2/arch/cris/boot/rescue/Makefile	Wed Dec 18 14:16:26 2002
@@ -53,7 +53,7 @@
 
 modules:
 
-modules-install:
+modules_install:
 
 depend:
 	$(CC) -M *.S > .depend
diff -urN linux-2.4.21-pre1/arch/cris/config.in linux-2.4.21-pre2/arch/cris/config.in
--- linux-2.4.21-pre1/arch/cris/config.in	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/config.in	Wed Dec 18 14:16:26 2002
@@ -154,6 +154,11 @@
 
 source drivers/md/Config.in
 
+source drivers/pcmcia/Config.in
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+   define_bool CONFIG_VIRTUAL_BUS y
+fi
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
diff -urN linux-2.4.21-pre1/arch/cris/drivers/Config.in linux-2.4.21-pre2/arch/cris/drivers/Config.in
--- linux-2.4.21-pre1/arch/cris/drivers/Config.in	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/Config.in	Wed Dec 18 14:16:26 2002
@@ -26,46 +26,150 @@
   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
+    if [ "$CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
       int '  Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
     fi
   fi
   bool '  Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0
   if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then
-    bool '  Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
-      int '    Ser0 RI  on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
-      int '    Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
-      int '    Ser0 CD  on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+  choice 'Ser0 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PA_BIT 4
+      int '    Ser0 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PA_BIT 5
+      int '    Ser0 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PA_BIT 6
+      int '    Ser0 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
+      int '    Ser0 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
+      int '    Ser0 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
+      int '    Ser0 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PB_BIT -1
     fi
   fi
 
   bool '  Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1
   if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then
-    bool '  Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
-      int '    Ser1 RI  on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
-      int '    Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
-      int '    Ser1 CD  on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+  choice 'Ser1 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PA_BIT 4
+      int '    Ser1 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PA_BIT 5
+      int '    Ser1 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PA_BIT 6
+      int '    Ser1 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
+      int '    Ser1 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
+      int '    Ser1 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
+      int '    Ser1 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PB_BIT -1
     fi
   fi
+
   if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \
        "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
     comment 'Make sure you dont have the same PB bits more than once!'
   fi
   bool '  Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2
   if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then
-    bool '    Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
-    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then
-      int '      Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
-      int '      Ser2 RI  on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
-      int '      Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
-      int '      Ser2 CD  on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
-    fi 
+  choice 'Ser2 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
+      int '    Ser2 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
+      int '    Ser2 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
+      int '    Ser2 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PB_BIT 4
+      int '    Ser2 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PB_BIT 5
+      int '    Ser2 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PB_BIT 6
+      int '    Ser2 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PB_BIT -1
+    fi
   fi
   bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
+  if [ "$CONFIG_ETRAX_SERIAL_PORT3" = "y" ]; then
+  choice 'Ser3 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      int '    Ser3 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      int '    Ser3 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      int '    Ser3 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      int '    Ser3 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      int '    Ser3 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      int '    Ser3 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    fi
+  fi
   bool '  RS-485 support' CONFIG_ETRAX_RS485
   if [ "$CONFIG_ETRAX_RS485" = "y" ]; then
     bool '    RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA
@@ -139,7 +243,6 @@
 	define_bool CONFIG_MTD y
 
 	define_bool CONFIG_MTD_CFI y
-	define_bool CONFIG_MTD_CFI_INTELEXT n
 	define_bool CONFIG_MTD_CFI_AMDSTD y
 
 	define_bool CONFIG_MTD_OBSOLETE_CHIPS y
@@ -148,6 +251,7 @@
 	define_bool CONFIG_MTD_CHAR y
 	define_bool CONFIG_MTD_BLOCK y
 	define_bool CONFIG_MTD_PARTITIONS y
+	define_bool CONFIG_MTD_CONCAT y
 fi
 
 bool 'I2C support' CONFIG_ETRAX_I2C
@@ -209,6 +313,7 @@
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
   int '  DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1
   int '  DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0
+  int '  DS1302 Trickle charger value' CONFIG_ETRAX_DS1302_TRICKLE_CHARGE 0
 fi
 
 endmenu
diff -urN linux-2.4.21-pre1/arch/cris/drivers/Makefile linux-2.4.21-pre2/arch/cris/drivers/Makefile
--- linux-2.4.21-pre1/arch/cris/drivers/Makefile	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/Makefile	Wed Dec 18 14:16:26 2002
@@ -18,6 +18,7 @@
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)  += sync_serial.o
 obj-$(CONFIG_ETRAX_PARPORT)             += parport.o
 obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
+obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
 
 
 obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
diff -urN linux-2.4.21-pre1/arch/cris/drivers/axisflashmap.c linux-2.4.21-pre2/arch/cris/drivers/axisflashmap.c
--- linux-2.4.21-pre1/arch/cris/drivers/axisflashmap.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/axisflashmap.c	Wed Dec 18 14:16:26 2002
@@ -11,6 +11,26 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.28  2002/10/01 08:08:43  jonashg
+ * The first partition ends at the start of the partition table.
+ *
+ * Revision 1.27  2002/08/21 09:23:13  jonashg
+ * Speling.
+ *
+ * Revision 1.26  2002/08/21 08:35:20  jonashg
+ * Cosmetic change to printouts.
+ *
+ * Revision 1.25  2002/08/21 08:15:42  jonashg
+ * Made it compile even without CONFIG_MTD_CONCAT defined.
+ *
+ * Revision 1.24  2002/08/20 13:12:35  jonashg
+ * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
+ *   the results.
+ * * Removed compile time tests concerning how the mtdram driver has been
+ *   configured. The user will know about the misconfiguration at runtime
+ *   instead. (The old approach made it impossible to use mtdram for anything
+ *   else than RAM boot).
+ *
  * Revision 1.23  2002/05/13 12:12:28  johana
  * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
  * be informative at runtime.
@@ -98,13 +118,15 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 
-#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
 #include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
+#include <asm/sv_addr_ag.h>
 
 #ifdef CONFIG_CRIS_LOW_MAP
 #define FLASH_UNCACHED_ADDR  KSEG_8
@@ -114,63 +136,65 @@
 #define FLASH_CACHED_ADDR    KSEG_F
 #endif
 
-/*
- * WINDOW_SIZE is the total size where the flash chips may be mapped.
- * MTD probes should find all devices there and it does not matter
- * if there are unmapped gaps or aliases (mirrors of flash devices).
- * The MTD probes will ignore them.
- */
-
-#define WINDOW_SIZE  (128 * 1024 * 1024)
-
-extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
 
-/* 
- * Map driver
- *
- * We run into tricky coherence situations if we mix cached with uncached
- * accesses to we use the uncached version here.
- */
+/* Map driver functions. */
 
 static __u8 flash_read8(struct map_info *map, unsigned long ofs)
 {
-	return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u8 *)(map->map_priv_1 + ofs);
 }
 
 static __u16 flash_read16(struct map_info *map, unsigned long ofs)
 {
-	return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u16 *)(map->map_priv_1 + ofs);
 }
 
 static __u32 flash_read32(struct map_info *map, unsigned long ofs)
 {
-	return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(volatile unsigned int *)(map->map_priv_1 + ofs);
 }
 
 static void flash_copy_from(struct map_info *map, void *to,
 			    unsigned long from, ssize_t len)
 {
-	memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
 }
 
 static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u8 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u16 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
-	*(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u32 *)(map->map_priv_1 + adr) = d;
 }
 
-static struct map_info axis_map = {
-	name: "Axis flash",
-	size: WINDOW_SIZE,
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+	name: "cse0",
+	size: MEM_CSE0_SIZE,
 	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
 	read8: flash_read8,
 	read16: flash_read16,
@@ -179,15 +203,35 @@
 	write8: flash_write8,
 	write16: flash_write16,
 	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR
 };
 
-/* If no partition-table was found, we use this default-set.
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
  */
+static struct map_info map_cse1 = {
+	name: "cse1",
+	size: MEM_CSE1_SIZE,
+	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
+	read8: flash_read8,
+	read16: flash_read16,
+	read32: flash_read32,
+	copy_from: flash_copy_from,
+	write8: flash_write8,
+	write16: flash_write16,
+	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
 
+/* If no partition-table was found, we use this default-set. */
 #define MAX_PARTITIONS         7  
 #define NUM_DEFAULT_PARTITIONS 3
 
-/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+/*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
  * size of one flash block and "filesystem"-partition needs 5 blocks to be able
  * to use JFFS.
  */
@@ -209,10 +253,11 @@
 	}
 };
 
+/* Initialize the ones normally used. */
 static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	{
 		name: "part0",
-		size: 0,
+		size: CONFIG_ETRAX_PTABLE_SECTOR,
 		offset: 0
 	},
 	{
@@ -247,48 +292,118 @@
 	},
 };
 
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+	struct mtd_info *mtd_cs = NULL;
+
+	printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+	       map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+	mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+	if (!mtd_cs) {
+		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	}
+#endif
+
+	return mtd_cs;
+}
+
 /* 
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
  */
-static struct mtd_info *mymtd;
+static struct mtd_info *flash_probe(void)
+{
+	struct mtd_info *mtd_cse0;
+	struct mtd_info *mtd_cse1;
+	struct mtd_info *mtd_cse;
+
+	mtd_cse0 = probe_cs(&map_cse0);
+	mtd_cse1 = probe_cs(&map_cse1);
+
+	if (!mtd_cse0 && !mtd_cse1) {
+		/* No chip found. */
+		return NULL;
+	}
+
+	if (mtd_cse0 && mtd_cse1) {
+#ifdef CONFIG_MTD_CONCAT
+		struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
+		
+		/* Since the concatenation layer adds a small overhead we
+		 * could try to figure out if the chips in cse0 and cse1 are
+		 * identical and reprobe the whole cse0+cse1 window. But since
+		 * flash chips are slow, the overhead is relatively small.
+		 * So we use the MTD concatenation layer instead of further
+		 * complicating the probing procedure.
+		 */
+		mtd_cse = mtd_concat_create(mtds,
+					    sizeof(mtds) / sizeof(mtds[0]),
+					    "cse0+cse1");
+#else
+		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+		mtd_cse = NULL;
+#endif
+		if (!mtd_cse) {
+			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+			       map_cse0.name, map_cse1.name);
+
+			/* The best we can do now is to only use what we found
+			 * at cse0.
+			 */ 
+			mtd_cse = mtd_cse0;
+			map_destroy(mtd_cse1);
+		}
+	} else {
+		mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
+	}
+
+	return mtd_cse;
+}
 
-/* CFI-scan the flash, and if there was a chip, read the partition-table
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
  * and register the partitions with MTD.
  */
-
-static int __init
-init_axis_flash(void)
+static int __init init_axis_flash(void)
 {
+	struct mtd_info *mymtd;
 	int err = 0;
 	int pidx = 0;
 	struct partitiontable_head *ptable_head;
 	struct partitiontable_entry *ptable;
-	int use_default_ptable = 1; /* Until proven otherwise */
-	const char *pmsg = "  /dev/flash%d at 0x%x, size 0x%x\n";
-
-	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
-	       WINDOW_SIZE, FLASH_CACHED_ADDR);
-#ifdef CONFIG_MTD_AMDSTD
-	mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map);
-#endif
+	int use_default_ptable = 1; /* Until proven otherwise. */
+	const char *pmsg = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
 
-#ifdef CONFIG_MTD_CFI
-	if (!mymtd) {
-		mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map);
+	if (!(mymtd = flash_probe())) {
+		/* There's no reason to use this module if no flash chip can
+		 * be identified. Make sure that's understood.
+		 */
+		panic("axisflashmap found no flash chip!\n");
 	}
-#endif
 
-	if(!mymtd) {
-		printk("%s: No flash chip found!\n", axis_map.name);
-		return -ENXIO;
-	}
+	printk("%s: 0x%08x bytes of flash memory.\n",
+	       mymtd->name, mymtd->size);
 
 	mymtd->module = THIS_MODULE;
 
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
-		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
-	pidx++;  /* first partition is always set to the default */
+		      CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
+	pidx++;  /* First partition is always set to the default. */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
 	    && (ptable_head->size <
@@ -322,20 +437,17 @@
 			csum += *p++;
 			csum += *p++;
 		}
-		/* printk("  total csum: 0x%08X 0x%08X\n",
-		   csum, ptable_head->checksum); */
 		ptable_ok = (csum == ptable_head->checksum);
 
 		/* Read the entries and use/show the info.  */
-		printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
-		       (ptable_ok ? "valid" : "invalid"),
-		       (unsigned long)ptable_head,
-		       (unsigned long)max_addr);
+		printk(" Found a%s partition table at 0x%p-0x%p.\n",
+		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
+		       max_addr);
 
 		/* We have found a working bootblock.  Now read the
-		   partition table.  Scan the table.  It ends when
-		   there is 0xffffffff, that is, empty flash.  */
-		
+		 * partition table.  Scan the table.  It ends when
+		 * there is 0xffffffff, that is, empty flash.
+		 */
 		while (ptable_ok
 		       && ptable->offset != 0xffffffff
 		       && ptable < max_addr
@@ -352,59 +464,64 @@
 		use_default_ptable = !ptable_ok;
 	}
 
+	if (romfs_in_flash) {
+		/* Add an overlapping device for the root partition (romfs). */
+
+		axis_partitions[pidx].name = "romfs";
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+		printk(" Adding readonly flash partition for romfs image:\n");
+		printk(pmsg, pidx, axis_partitions[pidx].offset,
+		       axis_partitions[pidx].size);
+		pidx++;
+	}
+
 	if (use_default_ptable) {
-		printk(" Using default partition table\n");
+		printk(" Using default partition table.\n");
 		err = add_mtd_partitions(mymtd, axis_default_partitions,
 		                         NUM_DEFAULT_PARTITIONS);
 	} else {
-		if (romfs_in_flash) {
-			axis_partitions[pidx].name = "romfs";
-			axis_partitions[pidx].size = romfs_length;
-			axis_partitions[pidx].offset = romfs_start -
-						       FLASH_CACHED_ADDR;
-			axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
-
-			printk(" Adding readonly partition for romfs image:\n");
-			printk(pmsg, pidx, axis_partitions[pidx].offset,
-			       axis_partitions[pidx].size);
-			pidx++;
-		}
-
 		err = add_mtd_partitions(mymtd, axis_partitions, pidx);
 	}
-	if (!err && !romfs_in_flash) {
-#ifdef CONFIG_MTD_MTDRAM
-		/* Allocate, initialise and forget the mtd ram struct
-		 * when booting from RAM
-		 */
-		struct mtd_info *romfs_mtd = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-		printk("MTD RAM device romfs_start: 0x%08lX len %lu\n",
-		       romfs_start, romfs_length);
 
-#if (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
-#error "You must set CONFIG_MTDRAM_TOTAL_SIZE and CONFIG_MTDRAM_ABS_POS to 0"
-#endif
-		err = mtdram_init_device(romfs_mtd, (void*)romfs_start, 
-		                         romfs_length, "romfs in RAM");
+	if (err) {
+		panic("axisflashmap could not add MTD partitions!\n");
+	}
+
+	if (!romfs_in_flash) {
+		/* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+		/* No use trying to boot this kernel from RAM. Panic! */
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device due to kernel (mis)configuration!\n");
+		panic("This kernel cannot boot from RAM!\n");
 #else
-#warning ######################################
-#warning # You must enable CONFIG_MTD_MTDRAM  #
-#warning # with TOTAL_SIZE 0 and ABS_POS 0 to # 
-#warning # be able to boot with cramfs in RAM #
-#warning ######################################
-/* Maybe overkill to save these bytes in non debug builds, but let's do it..
- * (No point in printing if we don't have a debug port anyway...)
- */
-#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
-		printk("## Can't mount romfs in RAM using MTDRAM.\n");
-		printk("## You must enable MTD_MTDRAM with TOTAL_SIZE 0 and ABS_POS 0\n");
+		struct mtd_info *mtd_ram;
+
+		mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+						     GFP_KERNEL);
+		if (!mtd_ram) {
+			panic("axisflashmap couldn't allocate memory for "
+			      "mtd_info!\n");
+		}
+
+		printk(" Adding RAM partition for romfs image:\n");
+		printk(pmsg, pidx, romfs_start, romfs_length);
+
+		err = mtdram_init_device(mtd_ram, (void*)romfs_start, 
+		                         romfs_length, "romfs");
+		if (err) {
+			panic("axisflashmap could not initialize MTD RAM "
+			      "device!\n");
+		}
 #endif
-#endif /* CONFIG_MTD_MTDRAM */
 	}
+
 	return err;
 }
 
-/* This adds the above to the kernels init-call chain */
-
+/* This adds the above to the kernels init-call chain. */
 module_init(init_axis_flash);
-
diff -urN linux-2.4.21-pre1/arch/cris/drivers/bluetooth/Makefile linux-2.4.21-pre2/arch/cris/drivers/bluetooth/Makefile
--- linux-2.4.21-pre1/arch/cris/drivers/bluetooth/Makefile	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/bluetooth/Makefile	Wed Dec 18 14:16:26 2002
@@ -1,19 +1,10 @@
-include $(APPS)/Rules.elinux
+include $(AXIS_TOP_DIR)/tools/build/Rules.axis
 
 all:
 
 install:	src/bluetooth.c include/btcommon.h
 	ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
-	if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
-	  echo '' >> ../Config.in; \
-	  echo '# The following if statement was added by arch/cris/drivers/bluetooth/Makefile' >> ../Config.in; \
-	  echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
-	  echo '  source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
-	  echo 'fi' >> ../Config.in; \
-	fi
-	if ! grep bluetooth/src/bt.o ../Makefile; then \
-	  perl -pi -e "s:include:\# The following two lines were added by arch/cris/drivers/bluetooth/Makefile\nobj-\\\$$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH)              += bluetooth/src\n\ninclude:" ../Makefile; \
-	fi
+	(cd .. && patch -N -r /tmp/bt.rej < bluetooth/bt.patch >/dev/null || true)
 
 clean:
 
diff -urN linux-2.4.21-pre1/arch/cris/drivers/bluetooth/bt.patch linux-2.4.21-pre2/arch/cris/drivers/bluetooth/bt.patch
--- linux-2.4.21-pre1/arch/cris/drivers/bluetooth/bt.patch	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/arch/cris/drivers/bluetooth/bt.patch	Wed Dec 18 14:16:26 2002
@@ -0,0 +1,33 @@
+Index: Config.in
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Config.in,v
+retrieving revision 1.46
+diff -u -d -r1.46 Config.in
+--- Config.in	11 Oct 2002 16:14:33 -0000	1.46
++++ Config.in	31 Oct 2002 08:44:37 -0000
+@@ -317,3 +317,8 @@
+ fi
+ 
+ endmenu
++
++# The following if statement was added by arch/cris/drivers/bluetooth/Makefile
++if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
++  source arch/cris/drivers/bluetooth/src/Config.in
++fi
+Index: Makefile
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Makefile,v
+retrieving revision 1.20
+diff -u -d -r1.20 Makefile
+--- Makefile	14 Aug 2002 18:32:33 -0000	1.20
++++ Makefile	31 Oct 2002 08:44:37 -0000
+@@ -24,5 +24,9 @@
+ obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
+ subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave
+ 
++# The following two lines were added by arch/cris/drivers/bluetooth/Makefile
++obj-$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o
++subdir-$(CONFIG_BLUETOOTH)              += bluetooth/src
++
+ include $(TOPDIR)/Rules.make
+ 
diff -urN linux-2.4.21-pre1/arch/cris/drivers/ds1302.c linux-2.4.21-pre2/arch/cris/drivers/ds1302.c
--- linux-2.4.21-pre1/arch/cris/drivers/ds1302.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/ds1302.c	Wed Dec 18 14:16:26 2002
@@ -7,6 +7,13 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.15  2002/10/11 16:14:33  johana
+*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
+*! trcklecharge register.
+*!
+*! Revision 1.14  2002/10/10 12:15:38  magnusmn
+*! Added support for having the RST signal on bit g0
+*!
 *! Revision 1.13  2002/05/29 15:16:08  johana
 *! Removed unused variables.
 *!
@@ -88,7 +95,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
+*! $Id: ds1302.c,v 1.15 2002/10/11 16:14:33 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -493,17 +500,25 @@
 { 
 	if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#if CONFIG_ETRAX_DS1302_RSTBIT == 27
 		/*
 		 * The only way to set g27 to output is to enable ATA.
 		 *
 		 * Make sure that R_GEN_CONFIG is setup correct.
 		 */
     		genconfig_shadow = ((genconfig_shadow &
-				     ~IO_MASK(R_GEN_CONFIG, ata))
-				   | 
+				     ~IO_MASK(R_GEN_CONFIG, ata)) | 
 				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
     		*R_GEN_CONFIG = genconfig_shadow;
-    		if (!ds1302_probe())
+#elif CONFIG_ETRAX_DS1302_RSTBIT == 0
+		
+		/* Set the direction of this bit to out. */		
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
+				   (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#endif
+		if (!ds1302_probe())
       			return -1;
 #else
     		return -1;
@@ -515,5 +530,8 @@
 		       ds1302_name, RTC_MAJOR_NR);
 		return -1;
 	}
+	/* Initialise trickle charger */
+	ds1302_writereg(RTC_TRICKLECHARGER,
+			RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
 	return 0;
 }
diff -urN linux-2.4.21-pre1/arch/cris/drivers/ethernet.c linux-2.4.21-pre2/arch/cris/drivers/ethernet.c
--- linux-2.4.21-pre1/arch/cris/drivers/ethernet.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/ethernet.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.30 2002/05/07 18:50:08 johana Exp $
+/* $Id: ethernet.c,v 1.34 2002/12/13 07:17:44 starvik Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,22 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.34  2002/12/13 07:17:44  starvik
+ * Basic ethtool and MII ioctls
+ * Handle out of memory when allocating new buffers
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
  * Revision 1.30  2002/05/07 18:50:08  johana
  * Correct spelling in comments.
  *
@@ -152,9 +168,12 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <linux/if.h>
+#include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
 #include <asm/io.h>         /* LED_* I/O functions */
@@ -163,6 +182,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/ethernet.h>
+#include <asm/cache.h>
+#include <asm/uaccess.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -264,10 +285,10 @@
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
@@ -304,12 +325,12 @@
 static int e100_open(struct net_device *dev);
 static int e100_set_mac_address(struct net_device *dev, void *addr);
 static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
 static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -324,6 +345,7 @@
 static void e100_negotiate(void);
 
 static unsigned short e100_get_mdio_reg(unsigned char reg_num);
+static void e100_set_mdio_reg(unsigned char reg, unsigned short data);
 static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
 static void e100_send_mdio_bit(unsigned char bit);
 static unsigned char e100_receive_mdio_bit(void);
@@ -399,11 +421,14 @@
 	/* Initialise receive descriptors */
 
 	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		/* Allocate two extra cachelines to make sure that buffer used by DMA
+		 * does not share cacheline with any other data (to avoid cache bug)
+		 */
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		RxDescList[i].descr.ctrl   = 0;
 		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
 		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].descr.buf    = virt_to_phys(RxDescList[i].skb->data);
+		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
 		RxDescList[i].descr.status = 0;
 		RxDescList[i].descr.hw_len = 0;
              
@@ -540,14 +565,14 @@
 
 	/* allocate the irq corresponding to the receiving DMA */
 
-	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit0;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
-	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit1;
 	}
@@ -685,9 +710,7 @@
 static void
 e100_negotiate(void)
 {
-	unsigned short cmd;
 	unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
-	int bitCounter;
 
 	/* Discard old speed and duplex settings */
 	data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
@@ -726,29 +749,13 @@
 			        MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
 	}
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_ADVERTISMENT_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}
+	e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data);
 
 	/* Renegotiate with link partner */
 	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
 	data |= MDIO_BC_NEGOTIATE;
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_BASE_CONTROL_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}  
+	e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data);
 }
 
 static void
@@ -816,6 +823,24 @@
 }
 
 static void
+e100_set_mdio_reg(unsigned char reg, unsigned short data)
+{
+	int bitCounter;
+	unsigned short cmd;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (reg << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+
+}
+
+static void
 e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
 {
 	int bitCounter;
@@ -958,21 +983,6 @@
 		*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
 		netif_stop_queue(dev);
 	}
-	else {
-	  /* Report any packets that have been sent */
-		while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		       myFirstTxDesc != myNextTxDesc)
-		{
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);				
-		}
-	}
 
 	spin_unlock_irq(&np->lock);
 
@@ -985,11 +995,13 @@
  */
 
 static void
-e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
  
+	/* Handle received packets */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 		/* acknowledge the eop interrupt */
 
@@ -1014,44 +1026,26 @@
 			   so we have to loop back and check if so */
 		}
 	}
-}
 
-/* the transmit dma channel interrupt
- *
- * this is supposed to free the skbuff which was pending during transmission,
- * and inform the kernel that we can send one more buffer
- */
+	/* Report any packets that have been sent */
+	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+	       myFirstTxDesc != myNextTxDesc)
+	{
+		np->stats.tx_bytes += myFirstTxDesc->skb->len;
+		np->stats.tx_packets++;
 
-static void
-e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	unsigned long irqbits = *R_IRQ_MASK2_RD;
-	struct net_local *np = (struct net_local *)dev->priv;
+		/* dma is ready with the transmission of the data in tx_skb, so now
+		   we can release the skb memory */
+		dev_kfree_skb_irq(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
 
-	/* check for a dma0_eop interrupt */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* Report all sent packets */
-		do {
-			/* acknowledge the eop interrupt */
-			*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb_irq(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-
-			if (netif_queue_stopped(dev)) {
-			  	/* Queue is running, disable tx IRQ */
-			  	*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
-				netif_wake_queue(dev);
-			}
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-		} while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		         myFirstTxDesc != myNextTxDesc);
+		/* acknowledge the eop interrupt and wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+		*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
+		netif_wake_queue(dev);
 	}
 }
 
@@ -1140,11 +1134,24 @@
 		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
 	}
 	else {
-		/* Large packet, send directly to upper layers and allocate new memory */		 
+		/* Large packet, send directly to upper layers and allocate new 
+		 * memory (aligned to cache line boundary to avoid bug).
+		 * Before sending the skb to upper layers we must make sure that 
+		 * skb->data points to the aligned start of the packet. 
+		 */
+		int align;  
+		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		if (!new_skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
 		skb = myNextRxDesc->skb;
-		skb_put(skb, length);
-		myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
-		myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data);
+		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;	
+		skb_put(skb, length + align); 
+		skb_pull(skb, align); /* Remove alignment bytes */
+		myNextRxDesc->skb = new_skb;
+		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
 	}
 
 	skb->dev = dev;
@@ -1220,8 +1227,22 @@
 static int
 e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	/* Maybe default should return -EINVAL instead? */
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+
 	switch (cmd) {
+		case SIOCETHTOOL:
+			return e100_ethtool_ioctl(dev,ifr);
+		case SIOCGMIIPHY: /* Get PHY address */
+			data->phy_id = MDIO_PHYS_ADDR;
+			break;
+		case SIOCGMIIREG: /* Read MII register */
+			data->val_out = e100_get_mdio_reg(data->reg_num);
+			break;
+		case SIOCSMIIREG: /* Write MII register */
+			e100_set_mdio_reg(data->reg_num, data->val_in);
+			break;
+		/* The ioctls below should be considered obsolete but are */
+		/* still present for compatability with old scripts/apps  */	
 		case SET_ETH_SPEED_10:                  /* 10 Mbps */
 			e100_set_speed(10);
 			break;
@@ -1240,10 +1261,90 @@
 		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
 			e100_set_duplex(autoneg);
 			break;
-		default: /* Auto neg */
-			e100_set_speed(0);
-			e100_set_duplex(autoneg);
-			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+		case ETHTOOL_GSET:
+		{
+			memset((void *) &ecmd, 0, sizeof (ecmd));
+			ecmd.supported = 
+			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = MDIO_PHYS_ADDR;
+			ecmd.speed = current_speed;
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+			ecmd.advertising = ADVERTISED_TP;
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				ecmd.advertising |= ADVERTISED_Autoneg;
+			else {
+				ecmd.advertising |= 
+				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+				if (current_speed_selection == 10)
+					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+				else if (current_speed_selection == 100)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+				if (current_duplex == half)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+				else if (current_duplex == full)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+			}
+			ecmd.autoneg = AUTONEG_ENABLE;
+			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_SSET:
+		{
+			if (!capable(CAP_NET_ADMIN)) {
+				return -EPERM;
+			}
+			if (ecmd.autoneg == AUTONEG_ENABLE) {
+				e100_set_duplex(autoneg);
+				e100_set_speed(0);
+			} else {
+				e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full);
+				e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100);
+			}
+		}
+		break;
+		case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info;
+			memset((void *) &info, 0, sizeof (info));
+			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+			strncpy(info.version, "$Rev$", sizeof(info.version) - 1);
+			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+			info.regdump_len = 0;
+			info.eedump_len = 0;
+			info.testinfo_len = 0;
+			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_NWAY_RST:
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				e100_negotiate();
+		break;
+		default:
+			return -EOPNOTSUPP;
+		break;
 	}
 	return 0;
 }
diff -urN linux-2.4.21-pre1/arch/cris/drivers/gpio.c linux-2.4.21-pre2/arch/cris/drivers/gpio.c
--- linux-2.4.21-pre1/arch/cris/drivers/gpio.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/gpio.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
+/* $Id: gpio.c,v 1.21 2002/12/02 08:11:41 starvik Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,29 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.21  2002/12/02 08:11:41  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.20  2002/10/16 21:16:24  johana
+ * Added support for PA high level interrupt.
+ * That gives 2ms response time with iodtest for high levels and 2-12 ms
+ * response time on low levels if the check is not made in
+ * process.c:cpu_idle() as well.
+ *
+ * Revision 1.19  2002/10/14 18:27:33  johana
+ * Implemented alarm handling so select() now works.
+ * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
+ * cpu_idle().
+ * Otherwise I get 15-18 ms (same as doing the poll in userspace -
+ * but less overhead).
+ * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
+ * is in 2.4) as well?
+ * TODO? Perhaps call request_irq()/free_irq() only when needed?
+ * Increased version to 2.5
+ *
+ * Revision 1.18  2002/10/11 15:02:00  johana
+ * Mask inverted 8 bit value in setget_input().
+ *
  * 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)
@@ -95,11 +118,19 @@
 #include <asm/svinto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/irq.h>
 
 #define GPIO_MAJOR 120  /* experimental MAJOR number */
 
 #define D(x)
 
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+	
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -137,6 +168,8 @@
 
 static struct gpio_private *alarmlist = 0;
 
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+
 /* Port A and B use 8 bit access, but Port G is 32 bit */
 #define NUM_PORTS (GPIO_MINOR_B+1)
 
@@ -197,21 +230,81 @@
 
 
 static unsigned int 
-gpio_poll(struct file *filp,
-	  struct poll_table_struct *wait)
+gpio_poll(struct file *file,
+	  poll_table *wait)
 {
-	/* TODO poll on alarms! */
-#if 0
-	if (!ANYTHING_WANTED) {
-		D(printk("gpio_select sleeping task\n"));
-		select_wait(&gpio_wq, table);
+	unsigned int mask = 0;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned long data;
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor == GPIO_MINOR_A) {
+		unsigned long tmp;
+		data = *R_PORT_PA_DATA;
+		/* PA has support for high level interrupt -
+		 * lets activate for those low and with highalarm set
+		 */
+		tmp = ~data & priv->highalarm & 0xFF;
+		*R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
+	} else if (priv->minor == GPIO_MINOR_B)
+		data = *R_PORT_PB_DATA;
+	else if (priv->minor == GPIO_MINOR_G)
+		data = *R_PORT_G_DATA;
+	else
 		return 0;
+	
+	if ((data & priv->highalarm) ||
+	    (~data & priv->lowalarm)) {
+		mask = POLLIN|POLLRDNORM;
+	}
+	
+	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+void etrax_gpio_wake_up_check(void)
+{
+	struct gpio_private *priv = alarmlist;
+	unsigned long data = 0;
+	while (priv) {
+		if (USE_PORTS(priv)) {
+			data = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			data = *R_PORT_G_DATA;
+		}
+		if ((data & priv->highalarm) ||
+		    (~data & priv->lowalarm)) {
+			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			wake_up_interruptible(&priv->alarm_wq);
+		}
+		priv = priv->next;
+	}
+}
+
+static void 
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
+	}
+}
+
+static void 
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long tmp;
+	/* Find what PA interrupts are active */
+	tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF;
+	/* Clear them.. */
+	/* NOTE: Maybe we need to be more careful here if some other
+	 * driver uses PA interrupt as well?
+	 */
+	*R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR);
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
 	}
-	D(printk("gpio_select ready\n"));
-#endif
-	return 1;
 }
 
+
 static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
                           loff_t *off)
 {
@@ -322,7 +415,7 @@
 {
 	struct gpio_private *p = alarmlist;
 	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
-
+	
 	/* unlink from alarmlist and free the private structure */
 
 	if (p == todel) {
@@ -334,7 +427,17 @@
 	}
 
 	kfree(todel);
-
+	/* Check if there are still any alarms set */
+	p = alarmlist;
+	while (p) {
+		if (p->highalarm | p->lowalarm) {
+			gpio_some_alarms = 1;
+			return 0;
+		}
+		p = p->next;
+	}
+	gpio_some_alarms = 0;
+		
 	return 0;
 }
 
@@ -353,7 +456,7 @@
 		*priv->dir = *priv->dir_shadow &= 
 		~((unsigned char)arg & priv->changeable_dir);
 		restore_flags(flags);
-		return ~(*priv->dir_shadow);
+		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
 	} else if (priv->minor == GPIO_MINOR_G) {
 		/* We must fiddle with R_GEN_CONFIG to change dir */
 		if (((arg & dir_g_in_bits) != arg) && 
@@ -491,10 +594,12 @@
 	case IO_HIGHALARM:
 		// set alarm when bits with 1 in arg go high
 		priv->highalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_LOWALARM:
 		// set alarm when bits with 1 in arg go low
 		priv->lowalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_CLRALARM:
 		// clear alarm for bits with 1 in arg
@@ -760,8 +865,21 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
-
+	printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
+	/* We call etrax_gpio_wake_up_check() from timer interrupt and
+	 * from cpu_idle() in kernel/process.c
+	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+	 * in some tests.
+	 */  
+	if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
+		printk("err: timer0 irq for gpio\n");
+	}
+	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
+		printk("err: PA irq for gpio\n");
+	}
+	
 	return res;
 }
 
diff -urN linux-2.4.21-pre1/arch/cris/drivers/i2c.c linux-2.4.21-pre2/arch/cris/drivers/i2c.c
--- linux-2.4.21-pre1/arch/cris/drivers/i2c.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/i2c.c	Wed Dec 18 14:16:26 2002
@@ -12,6 +12,12 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.9  2002/10/31 15:32:26  starvik
+*! Update Port B register and shadow even when running with hardware support
+*!   to avoid glitches when reading bits
+*! Never set direction to out in i2c_inbyte
+*! Removed incorrect clock togling at end of i2c_inbyte
+*!
 *! Revision 1.8  2002/08/13 06:31:53  starvik
 *! Made SDA and SCL line configurable
 *! Modified i2c_inbyte to work with PCF8563
@@ -47,7 +53,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
+/* $Id: i2c.c,v 1.9 2002/10/31 15:32:26 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -135,16 +141,24 @@
 
 /* enable or disable output-enable, to select output or input on the i2c bus */
 
-#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_))
-#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+#define i2c_dir_out() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); 
+#define i2c_dir_in() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
 
 /* control the i2c clock and data signals */
 
-#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x)))
+#define i2c_clk(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
 
-#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x)))
+#define i2c_data(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+	   ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
 
 /* read a bit from the i2c interface */
 
@@ -221,10 +235,11 @@
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
-		if (x & 0x80)
+		if (x & 0x80) {
 			i2c_data(I2C_DATA_HIGH);
-		else
+		} else {
 			i2c_data(I2C_DATA_LOW);
+		}
 		
 		i2c_delay(CLOCK_LOW_TIME/2);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -260,7 +275,6 @@
 
 	/* Enable I2C */
 	i2c_enable();
-	i2c_dir_out();
 	i2c_delay(CLOCK_LOW_TIME/2);
 
 	for (i = 1; i < 8; i++) {
@@ -281,12 +295,10 @@
 
 		/* Enable I2C */
 		i2c_enable();
-		i2c_dir_out();
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
-	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -416,7 +428,7 @@
 {
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
diff -urN linux-2.4.21-pre1/arch/cris/drivers/ide.c linux-2.4.21-pre2/arch/cris/drivers/ide.c
--- linux-2.4.21-pre1/arch/cris/drivers/ide.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/ide.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.24 2002/04/22 11:47:21 johana Exp $
+/* $Id: ide.c,v 1.26 2002/09/17 12:16:59 bjornw Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,12 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.26  2002/09/17 12:16:59  bjornw
+ * Removed unnecessary cli/sti pair
+ *
+ * Revision 1.25  2002/08/19 08:07:19  matsfg
+ * Added IN_WORD.
+ *
  * Revision 1.24  2002/04/22 11:47:21  johana
  * Fix according to 2.4.19-pre7. time_after/time_before and
  * missing end of comment.
@@ -180,9 +186,14 @@
 			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
 		timeleft--;
 }
-
 unsigned char 
 IN_BYTE(ide_ioreg_t reg) {
+        /* data was in the lower 16 bits in the status reg */
+        return (unsigned char)(IN_WORD(reg));
+}
+
+unsigned short 
+IN_WORD(ide_ioreg_t reg) {
 	int status;
 	int timeleft;
 
@@ -226,7 +237,7 @@
 
 	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
 
-	return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
+        return (unsigned short)status;
 }
 
 /* PIO timing (in R_ATA_CONFIG)
@@ -303,9 +314,6 @@
 	pio = 4;
 	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
 	
-	save_flags(flags);
-	cli();
-
 	/* set pio mode! */
   	 
 	switch(pio) {
@@ -350,7 +358,6 @@
 					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
 			break;
 	}
-	restore_flags(flags);
 }
 
 void __init 
@@ -816,13 +823,13 @@
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
 /*
diff -urN linux-2.4.21-pre1/arch/cris/drivers/parport.c linux-2.4.21-pre2/arch/cris/drivers/parport.c
--- linux-2.4.21-pre1/arch/cris/drivers/parport.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/parport.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.9 2002/05/15 12:30:24 starvik Exp $
+/* $Id: parport.c,v 1.10 2002/10/03 05:54:24 starvik Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -56,11 +56,11 @@
 //#define CONFIG_PAR0_INT 1
 //#define CONFIG_PAR1_INT 1
 
-#define SETF(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)
-
-#define SETS(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 struct etrax100par_struct {
 	/* parallell port control */
diff -urN linux-2.4.21-pre1/arch/cris/drivers/pcf8563.c linux-2.4.21-pre2/arch/cris/drivers/pcf8563.c
--- linux-2.4.21-pre1/arch/cris/drivers/pcf8563.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/pcf8563.c	Wed Dec 18 14:16:26 2002
@@ -15,7 +15,7 @@
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ * $Id: pcf8563.c,v 1.4 2002/10/15 09:22:42 tobiasa Exp $
  */
 
 #include <linux/config.h>
@@ -39,7 +39,11 @@
 #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$"
+#define DRIVER_VERSION "$Revision: 1.4 $"
+
+/* I2C bus slave registers. */
+#define RTC_I2C_READ		0xa3
+#define RTC_I2C_WRITE		0xa2
 
 /* Two simple wrapper macros, saves a few keystrokes. */
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
@@ -59,11 +63,38 @@
 	release: pcf8563_release,
 };
 
+unsigned char
+pcf8563_readreg(int reg) 
+{
+	unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
+
+	/* The PCF8563 does not return 0 for unimplemented bits */
+	switch(reg)
+	{
+		case RTC_SECONDS:
+		case RTC_MINUTES:
+		     res &= 0x7f;
+		     break;
+		case RTC_HOURS:
+		case RTC_DAY_OF_MONTH:
+		     res &= 0x3f;
+		     break;
+		case RTC_MONTH:
+		     res = (res & 0x1f) - 1;  /* PCF8563 returns month in range 1-12 */
+		     break;
+	}
+	return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val) 
+{
+	i2c_writereg(RTC_I2C_WRITE,reg,val);
+}
+
 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);
@@ -74,7 +105,7 @@
 	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_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;
@@ -93,8 +124,6 @@
 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 
@@ -134,7 +163,7 @@
 		return -1;
 	}
 
-	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
         
 	/* Check for low voltage, and warn about it.. */
 	if (rtc_read(RTC_SECONDS) & 0x80)
@@ -163,7 +192,7 @@
 pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Some sanity checks. */
-	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+	if (_IOC_TYPE(cmd) != RTC_MAGIC)
 		return -ENOTTY;
 
 	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
diff -urN linux-2.4.21-pre1/arch/cris/drivers/serial.c linux-2.4.21-pre2/arch/cris/drivers/serial.c
--- linux-2.4.21-pre1/arch/cris/drivers/serial.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/serial.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
+/* $Id: serial.c,v 1.44 2002/11/21 04:28:06 hp Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,42 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.44  2002/11/21 04:28:06  hp
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.43  2002/11/15 12:02:25  pkj
+ * Make sure we have a tty in flush_to_flip_buffer() before we
+ * try to use it...
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
  * Revision 1.37  2002/08/13 13:02:37  bjornw
  * Removed some warnings because of unused code
  *
@@ -321,7 +357,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.37 $";
+static char *serial_version = "$Revision: 1.44 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -429,7 +465,7 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
                     const unsigned char *buf, int count);
-static inline int raw_write(struct tty_struct * tty, int from_user,
+extern 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,
@@ -585,87 +621,214 @@
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 #endif
-  
 
-/* For now we assume that all bits are on the same port for each serial port */
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(R_PORT_PB_DATA):&dummy_ser[##line##]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Dummy shadow variables */
-#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_dir_ser0 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_dir_ser1 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_dir_ser2 = 0x00;
-#endif
+struct control_pins
+{
+	volatile unsigned char *dtr_port;
+	unsigned char          *dtr_shadow;
+	volatile unsigned char *ri_port;
+	unsigned char          *ri_shadow;
+	volatile unsigned char *dsr_port;
+	unsigned char          *dsr_shadow;
+	volatile unsigned char *cd_port;
+	unsigned char          *cd_shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] = 
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
+	},
 
-static unsigned char dummy_ser3 = 0x00;
-static unsigned char dummy_dir_ser3 = 0x00;
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
+	}
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Info needed for each ports extra control/status signals.
-   We only supports that all pins uses same register for each port */
 struct control_pins
 {
 	volatile unsigned char *port;
-	volatile unsigned char *shadow;
-	volatile unsigned char *dir_shadow;
+	unsigned char          *shadow;
 
-	unsigned char dtr_bit;
-	unsigned char ri_bit;
-	unsigned char dsr_bit;
-	unsigned char cd_bit;
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
 };
 
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
 static const struct control_pins e100_modem_pins[NR_PORTS] = 
 {
 	/* Ser 0 */
 	{
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
 #else
-		&dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
 	},
 
 	/* Ser 1 */
 	{
-#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
 #else
-		&dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
 	},
 
 	/* Ser 2 */
 	{
-#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-		R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
-		CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
 #else
-		&dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
 	},
 
 	/* Ser 3 */
 	{
-		&dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
 	}
 };
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
 
 #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
 unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
@@ -690,20 +853,16 @@
 
 /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
 /* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
 
 /* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
 
 /* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the memcpy_fromfs blocks while swapping in a page,
@@ -837,16 +996,17 @@
  * any general port.
  */
 
+
 static inline void 
 e100_dtr(struct e100_serial *info, int set)
 {
 #ifndef CONFIG_SVINTO_SIM
-	unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit);
+	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
 
 #ifdef SERIAL_DEBUG_IO  
 	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
 	printk("ser%i shadow before 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow,
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
 	       E100_DTR_GET(info));
 #endif
 	/* DTR is active low */
@@ -855,20 +1015,15 @@
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
+		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_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].dtr_bit, !set);
-#endif
 #ifdef SERIAL_DEBUG_IO
 	printk("ser%i shadow after 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow, 
+	       info->line, *e100_modem_pins[info->line].dtr_shadow, 
 	       E100_DTR_GET(info));
 #endif
 #endif
@@ -890,6 +1045,7 @@
 #endif
 }
 
+
 /* If this behaves as a modem, RI and CD is an output */
 static inline void 
 e100_ri_out(struct e100_serial *info, int set)
@@ -897,14 +1053,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* RI is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit);
+		unsigned char mask = e100_modem_pins[info->line].ri_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].ri_shadow &= ~mask;
+		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -915,14 +1071,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* CD is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit);
+		unsigned char mask = e100_modem_pins[info->line].cd_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].cd_shadow &= ~mask;
+		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -1078,23 +1234,49 @@
  * rs_stop() and rs_start()
  *
  * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
  * ------------------------------------------------------------
  */
 
-/* FIXME - when are these used and what is the purpose ? 
- * In rs_stop we probably just can block the transmit DMA ready irq
- * and in rs_start we re-enable it (and then the old one will come).
- */
-
 static void 
 rs_stop(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+		
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		restore_flags(flags);
+	}
 }
 
 static void 
 rs_start(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		
+		restore_flags(flags);
+	}
 }
 
 /*
@@ -1341,7 +1523,7 @@
 	return 1;
 }
 
-static _INLINE_ unsigned int
+extern _INLINE_ unsigned int
 handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
 {
 	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
@@ -1567,7 +1749,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
 		if (ireg & info->irq) {  
@@ -1613,7 +1795,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for both dma_eop and dma_descr for the input dma channel */
 		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
@@ -1671,10 +1853,10 @@
 	return 1;
 }
 
-static _INLINE_ void
+extern _INLINE_ void
 flush_to_flip_buffer(struct e100_serial *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty;
 	struct etrax_recv_buffer *buffer;
 	unsigned int length;
 	unsigned long flags;
@@ -1685,6 +1867,11 @@
 	save_flags(flags);
 	cli();
 
+	if (!(tty = info->tty)) {
+		restore_flags(flags);
+		return;
+	}
+
 	length = tty->flip.count;
 
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
@@ -1773,7 +1960,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (info->uses_dma) 
+		if (info->enabled && info->uses_dma) 
 			check_flush_timeout(info);
 	}
 } /* timeout_interrupt */
@@ -1880,7 +2067,7 @@
 
 */
 
-static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
+extern void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
 {
 	unsigned char rstat = info->port[REG_STATUS];
 
@@ -2247,6 +2434,7 @@
 change_speed(struct e100_serial *info)
 {
 	unsigned int cflag;
+	unsigned long xoff;
 
 	/* first some safety checks */
 	
@@ -2316,7 +2504,13 @@
 	
 	info->port[REG_TR_CTRL] = info->tx_ctrl;
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	*((unsigned long *)&info->port[REG_XOFF]) = 0;
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+	if (info->tty->termios->c_iflag & IXON ) {
+		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+	}
+	
+	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
 #endif /* !CONFIG_SVINTO_SIM */
 
 	update_char_time(info);
@@ -2349,7 +2543,7 @@
 	restore_flags(flags);
 }
 
-static inline int 
+extern inline int 
 raw_write(struct tty_struct * tty, int from_user,
 	  const unsigned char *buf, int count)
 {
@@ -2497,7 +2691,7 @@
 
 		/* Sleep until all sent */
 		tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_FAST_TIMER
 		/* Now sleep a little more so that shift register is empty */
 		schedule_usleep(info->char_time_usec * 2);
 #endif
@@ -2805,14 +2999,15 @@
 	       E100_DSR_GET(info),
 	       E100_CTS_GET(info));
 #endif
+
 	result =  
 		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
 		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
 		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-	
+
 #ifdef SERIAL_DEBUG_IO 
 	printk("e100ser: modem state: %i 0x%08X\n", result, result);
 	{
@@ -3488,7 +3683,7 @@
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct e100_serial *info)
+extern inline int line_info(char *buf, struct e100_serial *info)
 {
 	char	stat_buf[30];
 	int	ret;
@@ -3503,17 +3698,17 @@
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
-	if (E100_RTS_GET(info))
+	if (!E100_RTS_GET(info))
 		strcat(stat_buf, "|RTS");
-	if (E100_CTS_GET(info))
+	if (!E100_CTS_GET(info))
 		strcat(stat_buf, "|CTS");
-	if (E100_DTR_GET(info))
+	if (!E100_DTR_GET(info))
 		strcat(stat_buf, "|DTR");
-	if (E100_DSR_GET(info))
+	if (!E100_DSR_GET(info))
 		strcat(stat_buf, "|DSR");
-	if (E100_CD_GET(info))
+	if (!E100_CD_GET(info))
 		strcat(stat_buf, "|CD");
-	if (E100_RI_GET(info))
+	if (!E100_RI_GET(info))
 		strcat(stat_buf, "|RI");
 
 	ret += sprintf(buf+ret, " baud:%d", info->baud);
diff -urN linux-2.4.21-pre1/arch/cris/drivers/sync_serial.c linux-2.4.21-pre2/arch/cris/drivers/sync_serial.c
--- linux-2.4.21-pre1/arch/cris/drivers/sync_serial.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/drivers/sync_serial.c	Wed Dec 18 14:16:26 2002
@@ -64,13 +64,13 @@
 #define DEFAULT_FRAME_RATE 0
 #define DEFAULT_WORD_RATE 7
 
-#define DEBUG(x) 
+#define DEBUG(x)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 typedef struct sync_port
 {
@@ -107,8 +107,7 @@
 	char in_buffer[IN_BUFFER_SIZE];
 	volatile char* readp;  /* Next byte to be read by application */
 	volatile char* writep; /* Next byte to be written by etrax */
-	int odd_output; /* 1 if writing odd nible in 12 bit mode */
-	int odd_input;  /* 1 if reading odd nible in 12 bit mode */
+	int started; /* 1 if port has been started */
 } sync_port;
 
 
@@ -221,7 +220,6 @@
 	  IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
           IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
 	start_dma_in(&ports[0]);
 #else
@@ -229,7 +227,6 @@
 	initialize_port(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
 #endif
 
@@ -252,7 +249,6 @@
 	  IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
 	start_dma_in(&ports[1]);
 #else
@@ -263,7 +259,6 @@
 		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);	 
 #endif
 #endif
 
@@ -292,12 +287,12 @@
 	struct sync_port* port = &ports[portnbr];
 
 	DEBUG(printk("Init sync serial port %d\n", portnbr));
-    
+
+	port->started = 0;    
 	port->port_nbr = portnbr;	
 	port->busy = 0;		
 	port->readp = port->in_buffer;
-	port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
-	port->odd_input = 0;
+	port->writep = port->in_buffer;
 
 	init_waitqueue_head(&port->out_wait_q);
 	init_waitqueue_head(&port->in_wait_q);
@@ -422,6 +417,10 @@
 		case SSP_MODE:
 			if (arg > 5)
 				return -EINVAL;
+			if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)
+				*R_IRQ_MASK1_CLR = 1 << port->data_avail_bit;
+			else
+				*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
 			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
 			break;
 		case SSP_FRAME_SYNC:
@@ -466,8 +465,8 @@
 			if (arg & CLOCK_NOT_GATED)
 				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal);
 			else if (arg & CLOCK_GATED)
-				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);
-    
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);    
+
 			break;
 		case SSP_IPOLARITY:
 			if (arg & CLOCK_NORMAL)
@@ -553,11 +552,10 @@
 	copy_from_user(port->out_buffer, buf, count);
 	port->outp = port->out_buffer;
 	port->out_count = count;
-	port->odd_output = 1;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
-	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	send_word(port); /* Start sender by sending first word */
+	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
@@ -586,9 +584,15 @@
 
 	count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count;
 
-	/* Make sure transmitter is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+	/* Make sure transmitter/receiver is running */
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	if (!port->use_dma)
@@ -629,9 +633,14 @@
 
 	DEBUG(printk("Read dev %d count %d\n", dev, count));
 
-	/* Make sure receiver is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	/* Calculate number of available bytes */
@@ -680,13 +689,12 @@
 			*port->data_out = *port->outp++;
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
-			port->out_count--;
-			if (port->odd_output)
-				*port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1));
-			else
-				*port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1));
-			port->odd_output = !port->odd_output;
-			port->outp++;
+			{
+				int data = (*port->outp++) << 8;
+				data |= *port->outp++;
+				port->out_count-=2;  
+				*port->data_out = data;
+			}
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
 			port->out_count-=2;
@@ -710,7 +718,7 @@
 {
 	port->out_descr.hw_len = 0;
 	port->out_descr.next = 0;
-	port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
+	port->out_descr.ctrl = d_eol | d_eop | d_wait;
 	port->out_descr.sw_len = count;
 	port->out_descr.buf = virt_to_phys(port->out_buffer);
 	port->out_descr.status = 0;
@@ -765,6 +773,9 @@
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
 		sync_port *port = &ports[i];
+		if (!port->enabled)
+			continue;
+
 		if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */
 		{
 			/* Clear IRQ */
@@ -783,19 +794,15 @@
 
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
-		int update = 0;
 		sync_port *port = &ports[i];
 
 		if (!port->enabled)
-		{
 			continue;
-		}    
 
 		if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */
 		{
 			/* DMA has reached end of descriptor */
 			*port->input_dma_clr_irq = 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
 			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
 
 			/* Find out which descriptor that is ready */
@@ -847,18 +854,9 @@
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
 				{
 					int data = *(unsigned short *)port->data_in;
-					if (port->odd_input)
-					{
-						*port->writep |= (data & 0x0f00) >> 8;
-						*(port->writep + 1) = data & 0xff;
-					}
-					else
-					{
-						*port->writep = (data & 0x0ff0) >> 4;
-						*(port->writep + 1) = (data & 0x0f) << 4;
-					}
-					port->odd_input = !port->odd_input;
-					port->writep+=1;
+					*port->writep = (data & 0x0ff0) >> 4;
+					*(port->writep + 1) = data & 0x0f;
+					port->writep+=2;
 				}
 				break;
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
@@ -875,14 +873,14 @@
 					break;
 			}
 
-			if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
 				port->writep = port->in_buffer;
 			wake_up_interruptible(&port->in_wait_q); /* Wake up application */
 		}
 
 		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */
 		{
-			if (port->out_count) /* More data to send */
+			if (port->out_count > 0) /* More data to send */
 				send_word(port);
 			else /* transmission finished */
 			{
diff -urN linux-2.4.21-pre1/arch/cris/kernel/entry.S linux-2.4.21-pre2/arch/cris/kernel/entry.S
--- linux-2.4.21-pre1/arch/cris/kernel/entry.S	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/entry.S	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.39 2002/04/24 00:46:45 bjornw Exp $
+/* $Id: entry.S,v 1.40 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,9 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.40  2002/12/02 08:11:41  starvik
+ *  Merge of Linux 2.4.20
+ *
  *  Revision 1.39  2002/04/24 00:46:45  bjornw
  *  Added sys_tkill
  *
@@ -1016,7 +1019,33 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
-	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
+ 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_destroy */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_getevents */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_submit */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_cancel */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
 	
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -urN linux-2.4.21-pre1/arch/cris/kernel/fasttimer.c linux-2.4.21-pre2/arch/cris/kernel/fasttimer.c
--- linux-2.4.21-pre1/arch/cris/kernel/fasttimer.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/fasttimer.c	Wed Dec 18 14:16:26 2002
@@ -1,10 +1,13 @@
-/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+/* $Id: fasttimer.c,v 1.5 2002/10/15 06:21:39 starvik 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.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
  * Revision 1.4  2002/05/28 17:47:59  johana
  * Added del_fast_timer()
  *
@@ -551,6 +554,8 @@
   struct fast_timer t;
 #ifdef DECLARE_WAITQUEUE
   wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
   DECLARE_WAITQUEUE(wait, current);
 #else
   struct wait_queue *sleep_wait = NULL;
@@ -566,6 +571,9 @@
   set_current_state(TASK_RUNNING);
   remove_wait_queue(&sleep_wait, &wait);
   D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
 }
 
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.4.21-pre1/arch/cris/kernel/ksyms.c linux-2.4.21-pre2/arch/cris/kernel/ksyms.c
--- linux-2.4.21-pre1/arch/cris/kernel/ksyms.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/ksyms.c	Wed Dec 18 14:16:26 2002
@@ -24,6 +24,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern unsigned long get_cmos_time(void);
 extern void __Udiv(void);
+extern void __Umod(void);
 extern void __ashrdi3(void);
 extern void iounmap(void *addr);
 
@@ -47,9 +48,11 @@
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
 
 /* Math functions */
 EXPORT_SYMBOL(__Udiv);
+EXPORT_SYMBOL(__Umod);
 EXPORT_SYMBOL(__ashrdi3);
 
 /* Memory functions */
@@ -70,14 +73,13 @@
 EXPORT_SYMBOL(port_g_data_shadow);
 
 /* Userspace access functions */
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__generic_copy_from_user);
-EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
 EXPORT_SYMBOL(__copy_user_zeroing);
 EXPORT_SYMBOL(__copy_user);
 
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
+
 #undef memcpy
 #undef memset
 extern void * memset(void *, int, __kernel_size_t);
diff -urN linux-2.4.21-pre1/arch/cris/kernel/process.c linux-2.4.21-pre2/arch/cris/kernel/process.c
--- linux-2.4.21-pre1/arch/cris/kernel/process.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/process.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.22 2001/11/13 09:40:43 orjanf Exp $
+/* $Id: process.c,v 1.23 2002/10/14 18:29:27 johana Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,10 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.23  2002/10/14 18:29:27  johana
+ *  Call etrax_gpio_wake_up_check() from cpu_idle() to reduce gpio latency
+ *  from ~15 ms to ~6 ms.
+ *
  *  Revision 1.22  2001/11/13 09:40:43  orjanf
  *  Added dump_fpu (needed for core dumps).
  *
@@ -121,11 +125,18 @@
 {
 	hlt_counter--;
 }
- 
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
 int cpu_idle(void *unused)
 {
 	while(1) {
 		current->counter = -100;
+#ifdef CONFIG_ETRAX_GPIO
+		/* This can reduce latency from 15 ms to 6 ms */
+		etrax_gpio_wake_up_check(); /* drivers/gpio.c */
+#endif
 		schedule();
 	}
 }
diff -urN linux-2.4.21-pre1/arch/cris/kernel/setup.c linux-2.4.21-pre2/arch/cris/kernel/setup.c
--- linux-2.4.21-pre1/arch/cris/kernel/setup.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/setup.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
+/* $Id: setup.c,v 1.27 2002/10/11 12:57:15 pkj Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -232,33 +232,34 @@
 		info = &cpu_info[revision];
 
 	return seq_printf(m,
-		       "cpu\t\t: CRIS\n"
-		       "cpu revision\t: %lu\n"
-		       "cpu model\t: %s\n"
-		       "cache size\t: %d kB\n"
-		       "fpu\t\t: %s\n"
-		       "mmu\t\t: %s\n"
-		       "mmu DMA bug\t: %s\n"
-		       "ethernet\t: %s Mbps\n"
-		       "token ring\t: %s\n"
-		       "scsi\t\t: %s\n"
-		       "ata\t\t: %s\n"
-		       "usb\t\t: %s\n"
-		       "bogomips\t: %lu.%02lu\n",
-
-		       revision,
-		       info->model,
-		       info->cache,
-		       info->flags & HAS_FPU ? "yes" : "no",
-		       info->flags & HAS_MMU ? "yes" : "no",
-		       info->flags & HAS_MMU_BUG ? "yes" : "no",
-		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
-		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
-		       info->flags & HAS_SCSI ? "yes" : "no",
-		       info->flags & HAS_ATA ? "yes" : "no",
-		       info->flags & HAS_USB ? "yes" : "no",
-		       (loops_per_jiffy * HZ + 500) / 500000,
-		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+			  "processor\t: 0\n"
+			  "cpu\t\t: CRIS\n"
+			  "cpu revision\t: %lu\n"
+			  "cpu model\t: %s\n"
+			  "cache size\t: %d kB\n"
+			  "fpu\t\t: %s\n"
+			  "mmu\t\t: %s\n"
+			  "mmu DMA bug\t: %s\n"
+			  "ethernet\t: %s Mbps\n"
+			  "token ring\t: %s\n"
+			  "scsi\t\t: %s\n"
+			  "ata\t\t: %s\n"
+			  "usb\t\t: %s\n"
+			  "bogomips\t: %lu.%02lu\n",
+
+			  revision,
+			  info->model,
+			  info->cache,
+			  info->flags & HAS_FPU ? "yes" : "no",
+			  info->flags & HAS_MMU ? "yes" : "no",
+			  info->flags & HAS_MMU_BUG ? "yes" : "no",
+			  info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+			  info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+			  info->flags & HAS_SCSI ? "yes" : "no",
+			  info->flags & HAS_ATA ? "yes" : "no",
+			  info->flags & HAS_USB ? "yes" : "no",
+			  (loops_per_jiffy * HZ + 500) / 500000,
+			  ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
diff -urN linux-2.4.21-pre1/arch/cris/kernel/signal.c linux-2.4.21-pre2/arch/cris/kernel/signal.c
--- linux-2.4.21-pre1/arch/cris/kernel/signal.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/signal.c	Wed Dec 18 14:16:26 2002
@@ -517,7 +517,7 @@
  * OK, we're invoking a handler
  */	
 
-static inline void
+extern inline void
 handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
diff -urN linux-2.4.21-pre1/arch/cris/kernel/time.c linux-2.4.21-pre2/arch/cris/kernel/time.c
--- linux-2.4.21-pre1/arch/cris/kernel/time.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/time.c	Wed Dec 18 14:16:26 2002
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.14 2002/03/05 13:31:03 johana Exp $
+/* $Id: time.c,v 1.17 2002/11/15 14:49:24 oskarp Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001, 2002 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -25,6 +25,9 @@
  *      resolution within a jiffie as well.
  * 2002-03-05    Johan Adolfsson
  *      Use prescaler in do_slow_gettimeoffset() to get 1 us resolution (40ns)
+ * 2002-09-06    Johan Adolfsson
+ *      Handle lost ticks by checking wall_jiffies, more efficient code 
+ *      by using local vars and not the pointer argument.
  *
  */
 
@@ -62,6 +65,8 @@
 
 #define TICK_SIZE tick
 
+extern unsigned long wall_jiffies;
+
 /* The timers count from their initial value down to 1 
  * The R_TIMER0_DATA counts down when R_TIM_PRESC_STATUS reaches halv
  * of the divider value.
@@ -171,10 +176,8 @@
 
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are three kinds of problems that must be avoided here:
+	 * there are one problem that must be avoided here:
 	 *  1. the timer counter underflows
-	 *  2. we are after the timer interrupt, but the bottom half handler
-	 *     hasn't executed yet.
 	 */
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
@@ -198,7 +201,8 @@
 	return usec_count;
 }
 
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+#define do_gettimeoffset() do_slow_gettimeoffset()
 
 /*
  * This version of gettimeofday has near microsecond resolution.
@@ -206,20 +210,33 @@
 void do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags;
-
+	unsigned long usec, sec;
 	save_flags(flags);
 	cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
 	restore_flags(flags);
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
+	unsigned long flags;
+	signed long new_usec, new_sec;
+	save_flags(flags);  
 	cli();
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
@@ -227,20 +244,23 @@
 	 * Discover what correction gettimeofday
 	 * would have done, and then undo it!
 	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	if (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
+	new_usec = tv->tv_usec;
+	new_usec -= do_gettimeoffset();
+	new_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	new_sec = tv->tv_sec;
+	while (new_usec < 0) {
+		new_usec += 1000000;
+		new_sec--;
 	}
+	xtime.tv_sec = new_sec;
+	xtime.tv_usec = new_usec;
 
-	xtime = *tv;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_state = TIME_ERROR;	/* p. 24, (a) */
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	restore_flags(flags);
 }
 
 
@@ -479,10 +499,16 @@
 void __init
 time_init(void)
 {	
-	/* probe for the RTC and read it if it exists */
+	/* Probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
 
 	if(RTC_INIT() < 0) {
-		/* no RTC, start at 1980 */
+		/* no RTC, start at the Epoch (00:00:00 UTC, January 1, 1970) */
 		xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 		have_rtc = 0;
diff -urN linux-2.4.21-pre1/arch/cris/kernel/traps.c linux-2.4.21-pre2/arch/cris/kernel/traps.c
--- linux-2.4.21-pre1/arch/cris/kernel/traps.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/kernel/traps.c	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.17 2001/12/07 17:02:34 bjornw Exp $
+/* $Id: traps.c,v 1.18 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/traps.c
  *
diff -urN linux-2.4.21-pre1/arch/cris/lib/dram_init.S linux-2.4.21-pre2/arch/cris/lib/dram_init.S
--- linux-2.4.21-pre1/arch/cris/lib/dram_init.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/lib/dram_init.S	Wed Dec 18 14:16:26 2002
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
+/* $Id: dram_init.S,v 1.13 2002/10/30 07:42:28 starvik Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.13  2002/10/30 07:42:28  starvik
+ * Always read SDRAM command sequence from flash
+ *
  * Revision 1.12  2002/08/09 11:37:37  orjanf
  * Added double initialization work-around for Samsung SDRAMs.
  *
@@ -143,7 +146,9 @@
 	
 	; Issue initialization command sequence
 	move.d   _sdram_commands_start, $r2
+	and.d    0x00ffffff, $r2 ; Make sure commands are read from flash
 	move.d   _sdram_commands_end,  $r3
+	and.d    0x00ffffff, $r2
 1:	clear.d  $r4
 	move.b   [$r2+], $r4
 	lslq     9, $r4	; Command starts at bit 9
diff -urN linux-2.4.21-pre1/arch/cris/lib/hw_settings.S linux-2.4.21-pre2/arch/cris/lib/hw_settings.S
--- linux-2.4.21-pre1/arch/cris/lib/hw_settings.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/cris/lib/hw_settings.S	Wed Dec 18 14:16:26 2002
@@ -1,11 +1,11 @@
 /*
- * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
+ * $Id: hw_settings.S,v 1.5 2002/08/15 09:16:06 bjornw Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
  * Don't forget to update the tools if you change this table.
  *
- * Copyright (C) 2001 Axis Communications AB
+ * Copyright (C) 2001, 2002 Axis Communications AB
  *
  * Authors:  Mikael Starvik (starvik@axis.com)	
  */
@@ -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 CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"	; Magic number
+	.dword 0xc0004000	; Where to load the kernel image (physical!)
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -urN linux-2.4.21-pre1/arch/cris/lib/usercopy.c linux-2.4.21-pre2/arch/cris/lib/usercopy.c
--- linux-2.4.21-pre1/arch/cris/lib/usercopy.c	Mon Oct  8 11:43:54 2001
+++ linux-2.4.21-pre2/arch/cris/lib/usercopy.c	Wed Dec 18 14:16:26 2002
@@ -88,11 +88,11 @@
        If you want to check that the allocation was right; then
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12".  */
-    __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+    __asm__ volatile ("\
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -189,7 +189,8 @@
 }
 
 /* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  */
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
 
 unsigned long
 __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn)
@@ -207,30 +208,34 @@
   register int n __asm__ ("r12") = pn;
   register int retn __asm__ ("r10") = 0;
 
-  /* When src is aligned but not dst, this makes a few extra needless
-     cycles.  I believe it would take as many to check that the
-     re-alignment was unnecessary.  */
-  if (((unsigned long) dst & 3) != 0
-      /* Don't align if we wouldn't copy more than a few bytes; so we
-	 don't have to check further for overflows.  */
-      && n >= 3)
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
   {
-    if ((unsigned long) dst & 1)
+    if (((unsigned long) src & 1) && n != 0)
     {
       __asm_copy_from_user_1 (dst, src, retn);
       n--;
     }
 
-    if ((unsigned long) dst & 2)
+    if (((unsigned long) src & 2) && n >= 2)
     {
       __asm_copy_from_user_2 (dst, src, retn);
       n -= 2;
     }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
   }
 
   /* Decide which copying method to use. */
   if (n >= 44*2)		/* Break even between movem and
-				   move16 is at 38.7*2, but modulo 44. */
+				   move16 is at 38.7*2, but modulo 44.
+				   FIXME: We use move4 now.  */
   {
     /* For large copies we use 'movem' */
 
@@ -249,10 +254,10 @@
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12" */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -273,73 +278,30 @@
 	movem	$r10,[$r13+]
 
 	addq   44,$r12  ;; compensate for last loop underflowing n
-8:
+
 	;; Restore registers from stack
 	movem [$sp+],$r10
-
+4:
 	.section .fixup,\"ax\"
 
 ;; Do not jump back into the loop if we fail.  For some uses, we get a
-;; page fault but for performance reasons we care to not get further
-;; faults.  For example, fs/super.c at one time did
+;; page fault somewhere on the line.  Without checking for page limits,
+;; we don't know where, but we need to copy accurately and keep an
+;; accurate count; not just clear the whole line.  To do that, we fall
+;; down in the code below, proceeding with smaller amounts.  It should
+;; be kept in mind that we have to cater to code like what at one time
+;; was in fs/super.c:
 ;;  i = size - copy_from_user((void *)page, data, size);
 ;; which would cause repeated faults while clearing the remainder of
 ;; the SIZE bytes at PAGE after the first fault.
+;; A caveat here is that we must not fall through from a failing page
+;; to a valid page.
 
 3:
-	move.d [$sp],$r10
-
-;; Number of remaining bytes, cleared but not copied, is r12 + 44.
-
-	add.d $r12,$r10
-	addq 44,$r10
-
-	move.d $r10,[$sp]
-	clear.d $r0
-	clear.d $r1
-	clear.d $r2
-	clear.d $r3
-	clear.d $r4
-	clear.d $r5
-	clear.d $r6
-	clear.d $r7
-	clear.d $r8
-	clear.d $r9
-	clear.d $r10
-
-;; Perform clear similar to the copy-loop.
-
-4:
-	subq 44,$r12
-	bge 4b
-	movem $r10,[$r13+]
-
-;; Clear by four for the remaining multiples.
-
-	addq 40,$r12
-	bmi 6f
-	nop
-5:
-	subq 4,$r12
-	bpl 5b
-	clear.d [$r13+]
-6:
-	addq 4,$r12
-	beq 7f
-	nop
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	clear.d $r12
-	clear.b [$r13+]
-7:
-	jump 8b
+	movem  [$sp+],$r10
+	addq	44,$r12 ;; Get back count before faulting point.
+	subq	44,$r11 ;; Get back pointer to faulting movem-line.
+	jump	4b	;; Fall through, pretending the fault didn't happen.
 
 	.previous
 	.section __ex_table,\"a\"
@@ -354,25 +316,30 @@
   /* Either we directly start copying here, using dword copying in a loop,
      or we copy as much as possible with 'movem' and then the last block
      (<44 bytes) is copied here.  This will work since 'movem' will have
-     updated src, dst and n. */
+     updated src, dst and n.  (Except with failing src.)
 
-  while (n >= 16)
-  {
-    __asm_copy_from_user_16 (dst, src, retn);
-    n -= 16;
-  }
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
 
-  /* Having a separate by-four loops cuts down on cache footprint.
-     FIXME:  Test with and without; increasing switch to be 0..15.  */
   while (n >= 4)
   {
     __asm_copy_from_user_4 (dst, src, retn);
     n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
   }
 
+  /* If we get here, there were no memory read faults.  */
   switch (n)
   {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
     case 0:
+      /* This case deliberately left in (if you have doubts check the
+	 generated assembly code).  */
       break;
     case 1:
       __asm_copy_from_user_1 (dst, src, retn);
@@ -385,7 +352,22 @@
       break;
   }
 
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
   return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
 }
 
 /* Zero userspace.  */
@@ -444,10 +426,10 @@
       check the equalities in the first comment.  It should say
       something like "r13=r13, r11=r11, r12=r12". */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r12 %2=r10
-	;;
+	.ifnc %0%1%2,$r13$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll clobber in the movem process
 	;; on the stack.  Don't mention them to gcc, it will only be
 	;; upset.
diff -urN linux-2.4.21-pre1/arch/cris/mm/ioremap.c linux-2.4.21-pre2/arch/cris/mm/ioremap.c
--- linux-2.4.21-pre1/arch/cris/mm/ioremap.c	Tue May  1 16:04:56 2001
+++ linux-2.4.21-pre2/arch/cris/mm/ioremap.c	Wed Dec 18 14:16:26 2002
@@ -13,7 +13,7 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
 {
 	unsigned long end;
diff -urN linux-2.4.21-pre1/arch/i386/config.in linux-2.4.21-pre2/arch/i386/config.in
--- linux-2.4.21-pre1/arch/i386/config.in	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/arch/i386/config.in	Wed Dec 18 14:16:26 2002
@@ -222,7 +222,7 @@
       bool ' Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
       if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
          define_bool CONFIG_X86_CLUSTERED_APIC y
-		 define_bool CONFIG_MULTIQUAD y
+         define_bool CONFIG_MULTIQUAD y
       fi
       bool ' IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT
       if [ "$CONFIG_X86_SUMMIT" = "y" ]; then
@@ -231,9 +231,11 @@
    fi
 fi
 
-bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
-if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
-   define_bool CONFIG_X86_TSC y
+if [ "$CONFIG_X86_NUMA" != "y" ]; then
+   bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
+   if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
+      define_bool CONFIG_X86_TSC y
+   fi
 fi
 
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
diff -urN linux-2.4.21-pre1/arch/i386/kernel/head.S linux-2.4.21-pre2/arch/i386/kernel/head.S
--- linux-2.4.21-pre1/arch/i386/kernel/head.S	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/i386/kernel/head.S	Wed Dec 18 14:16:26 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/i386/head.S -- the 32-bit startup code.
+ *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
diff -urN linux-2.4.21-pre1/arch/i386/kernel/mpparse.c linux-2.4.21-pre2/arch/i386/kernel/mpparse.c
--- linux-2.4.21-pre1/arch/i386/kernel/mpparse.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/arch/i386/kernel/mpparse.c	Wed Dec 18 14:16:26 2002
@@ -36,18 +36,20 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+int *mp_bus_id_to_type;
+int *mp_bus_id_to_node;
+int *mp_bus_id_to_local;
+int *mp_bus_id_to_pci_bus;
+int max_mp_busses;
+int max_irq_sources;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mpc_config_intsrc *mp_irqs;
 
 /* MP IRQ source entries */
 int mp_irq_entries;
@@ -232,7 +234,7 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
-			--num_processors;
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
@@ -313,7 +315,7 @@
 			m->mpc_irqtype, m->mpc_irqflag & 3,
 			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
 			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+	if (++mp_irq_entries == max_irq_sources)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
@@ -406,6 +408,9 @@
 	char oem[16], prod[14];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
+	int num_bus = 0;
+	int num_irq = 0;
+	unsigned char *bus_data;
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -453,9 +458,70 @@
 		mpc_record = 0;
 	}
 
+	/* Pre-scan to determine the number of bus and 
+	 * interrupts records we have
+	 */
+	while (count < mpc->mpc_length) {
+		switch (*mpt) {
+			case MP_PROCESSOR:
+				mpt += sizeof(struct mpc_config_processor);
+				count += sizeof(struct mpc_config_processor);
+				break;
+			case MP_BUS:
+				++num_bus;
+				mpt += sizeof(struct mpc_config_bus);
+				count += sizeof(struct mpc_config_bus);
+				break;
+			case MP_INTSRC:
+				++num_irq;
+				mpt += sizeof(struct mpc_config_intsrc);
+				count += sizeof(struct mpc_config_intsrc);
+				break;
+			case MP_IOAPIC:
+				mpt += sizeof(struct mpc_config_ioapic);
+				count += sizeof(struct mpc_config_ioapic);
+				break;
+			case MP_LINTSRC:
+				mpt += sizeof(struct mpc_config_lintsrc);
+				count += sizeof(struct mpc_config_lintsrc);
+				break;
+			default:
+				count = mpc->mpc_length;
+				break;
+		}
+	}
+	/* 
+	 * Paranoia: Allocate one extra of both the number of busses and number
+	 * of irqs, and make sure that we have at least 4 interrupts per PCI
+	 * slot.  But some machines do not report very many busses, so we need
+	 * to fall back on the older defaults.
+	 */
+	++num_bus;
+	max_mp_busses = max(num_bus, MAX_MP_BUSSES);
+	if (num_irq < (4 * max_mp_busses))
+		num_irq = 4 * num_bus;	/* 4 intr/PCI slot */
+	++num_irq;
+	max_irq_sources = max(num_irq, MAX_IRQ_SOURCES);
+	
+	count = (max_mp_busses * sizeof(int)) * 4;
+	count += (max_irq_sources * sizeof(struct mpc_config_intsrc));
+	bus_data = alloc_bootmem(count);
+	if (!bus_data) {
+		printk(KERN_ERR "SMP mptable: out of memory!\n");
+		return 0;
+	}
+	mp_bus_id_to_type = (int *)&bus_data[0];
+	mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))];
+	mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2];
+	mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3];
+	mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4];
+	memset(mp_bus_id_to_pci_bus, -1, max_mp_busses);
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
+	count = sizeof(*mpc);
+	mpt = ((unsigned char *)mpc)+count;
 	while (count < mpc->mpc_length) {
 		switch(*mpt) {
 			case MP_PROCESSOR:
diff -urN linux-2.4.21-pre1/arch/i386/kernel/smpboot.c linux-2.4.21-pre2/arch/i386/kernel/smpboot.c
--- linux-2.4.21-pre1/arch/i386/kernel/smpboot.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/arch/i386/kernel/smpboot.c	Wed Dec 18 14:16:26 2002
@@ -410,7 +410,7 @@
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	/*
 	 * Because we use NMIs rather than the INIT-STARTUP sequence to
-	 * bootstrap the CPUs, the APIC may be in a wierd state. Kick it.
+	 * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
 	 */
 	if (clustered_apic_mode)
 		clear_local_APIC();
diff -urN linux-2.4.21-pre1/arch/i386/kernel/time.c linux-2.4.21-pre2/arch/i386/kernel/time.c
--- linux-2.4.21-pre1/arch/i386/kernel/time.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/arch/i386/kernel/time.c	Wed Dec 18 14:16:26 2002
@@ -256,12 +256,177 @@
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
+
+/* IBM Summit (EXA) Cyclone Timer code*/
+#ifdef CONFIG_X86_SUMMIT
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0
+#define CYCLONE_PMCC_OFFSET 0x51A0
+#define CYCLONE_MPMC_OFFSET 0x51D0
+#define CYCLONE_MPCS_OFFSET 0x51A8
+#define CYCLONE_TIMER_FREQ 100000000
+
+int use_cyclone = 0;
+int __init cyclone_setup(char *str) 
+{
+	use_cyclone = 1;
+	return 1;
+}
+
+static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+static u32 last_cyclone_timer;
+
+static inline void mark_timeoffset_cyclone(void)
+{
+	int count;
+	spin_lock(&i8253_lock);
+	/* quickly read the cyclone timer */
+	if(cyclone_timer)
+		last_cyclone_timer = cyclone_timer[0];
+
+	/* calculate delay_at_last_interrupt */
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+static unsigned long do_gettimeoffset_cyclone(void)
+{
+	u32 offset;
+
+	if(!cyclone_timer)
+		return delay_at_last_interrupt;
+
+	/* Read the cyclone timer */
+	offset = cyclone_timer[0];
+
+	/* .. relative to previous jiffy */
+	offset = offset - last_cyclone_timer;
+
+	/* convert cyclone ticks to microseconds */	
+	/* XXX slow, can we speed this up? */
+	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + offset;
+}
+
+static void __init init_cyclone_clock(void)
+{
+	u32* reg;	
+	u32 base;		/* saved cyclone base address */
+	u32 pageaddr;	/* page that contains cyclone_timer register */
+	u32 offset;		/* offset from pageaddr to cyclone_timer register */
+	int i;
+	
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address */
+	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
+	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	base = *reg;	
+	if(!base){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		use_cyclone = 0;
+		return;
+	}
+	
+	/* setup PMCC */
+	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* setup MPCS */
+	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* map in cyclone_timer */
+	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!cyclone_timer){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+
+	/*quick test to make sure its ticking*/
+	for(i=0; i<3; i++){
+		u32 old = cyclone_timer[0];
+		int stall = 100;
+		while(stall--) barrier();
+		if(cyclone_timer[0] == old){
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			cyclone_timer = 0;
+			use_cyclone = 0;
+			return;
+		}
+	}
+	/* Everything looks good, so set do_gettimeoffset */
+	do_gettimeoffset = do_gettimeoffset_cyclone;	
+}
+void __cyclone_delay(unsigned long loops)
+{
+	unsigned long bclock, now;
+	if(!cyclone_timer)
+		return;
+	bclock = cyclone_timer[0];
+	do {
+		rep_nop();
+		now = cyclone_timer[0];
+	} while ((now-bclock) < loops);
+}
+#endif /* CONFIG_X86_SUMMIT */
+
 #else
 
 #define do_gettimeoffset()	do_fast_gettimeoffset()
 
 #endif
 
+/* No-cyclone stubs */
+#ifndef CONFIG_X86_SUMMIT
+int __init cyclone_setup(char *str) 
+{
+	printk(KERN_ERR "cyclone: Kernel not compiled with CONFIG_X86_SUMMIT, cannot use the cyclone-timer.\n");
+	return 1;
+}
+
+const int use_cyclone = 0;
+static void mark_timeoffset_cyclone(void) {}
+static unsigned long do_gettimeoffset_cyclone(void) {return 0;}
+static void init_cyclone_clock(void) {}
+void __cyclone_delay(unsigned long loops) {}
+#endif /* CONFIG_X86_SUMMIT */
+
 /*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
@@ -481,8 +646,9 @@
 	 */
 	write_lock(&xtime_lock);
 
-	if (use_tsc)
-	{
+	if(use_cyclone)
+		mark_timeoffset_cyclone();
+	else if (use_tsc) {
 		/*
 		 * It is important that these two operations happen almost at
 		 * the same time. We do the RDTSC stuff first, since it's
@@ -531,7 +697,7 @@
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 	}
- 
+
 	do_timer_interrupt(irq, NULL, regs);
 
 	write_unlock(&xtime_lock);
@@ -692,21 +858,30 @@
  	 */
  
  	dodgy_tsc();
- 	
+
+ 	if(use_cyclone)
+		init_cyclone_clock();
+		
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
 		if (tsc_quotient) {
 			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
+			/* XXX: This is messy
+			 * However, we want to allow for the cyclone timer 
+			 * to work w/ or w/o the TSCs being avaliable
+			 *      -johnstul@us.ibm.com
 			 */
-			x86_udelay_tsc = 1;
+			if(!use_cyclone){
+				/*
+				 *	We could be more selective here I suspect
+				 *	and just enable this for the next intel chips ?
+			 	 */
+				use_tsc = 1;
+				x86_udelay_tsc = 1;
 #ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
+				do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-
+			}
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
 			 * clock/second. Our precision is about 100 ppm.
@@ -721,6 +896,7 @@
 		}
 	}
 
+
 #ifdef CONFIG_VISWS
 	printk("Starting Cobalt Timer system clock\n");
 
diff -urN linux-2.4.21-pre1/arch/i386/lib/delay.c linux-2.4.21-pre2/arch/i386/lib/delay.c
--- linux-2.4.21-pre1/arch/i386/lib/delay.c	Sun Aug 12 10:29:44 2001
+++ linux-2.4.21-pre2/arch/i386/lib/delay.c	Wed Dec 18 14:16:26 2002
@@ -56,10 +56,13 @@
 		:"=&a" (d0)
 		:"0" (loops));
 }
-
+extern __cyclone_delay(unsigned long loops);
+extern int use_cyclone;
 void __delay(unsigned long loops)
 {
-	if (x86_udelay_tsc)
+	if (use_cyclone)
+		__cyclone_delay(loops);
+	else if (x86_udelay_tsc)
 		__rdtsc_delay(loops);
 	else
 		__loop_delay(loops);
diff -urN linux-2.4.21-pre1/arch/i386/mm/init.c linux-2.4.21-pre2/arch/i386/mm/init.c
--- linux-2.4.21-pre1/arch/i386/mm/init.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/i386/mm/init.c	Wed Dec 18 14:16:26 2002
@@ -356,7 +356,7 @@
 
 #if CONFIG_X86_PAE
 	/*
-	 * We will bail out later - printk doesnt work right now so
+	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
 	 */
 	if (cpu_has_pae)
diff -urN linux-2.4.21-pre1/arch/ia64/boot/bootloader.c linux-2.4.21-pre2/arch/ia64/boot/bootloader.c
--- linux-2.4.21-pre1/arch/ia64/boot/bootloader.c	Tue Jul 31 10:30:08 2001
+++ linux-2.4.21-pre2/arch/ia64/boot/bootloader.c	Wed Dec 18 14:16:26 2002
@@ -53,6 +53,15 @@
 
 #include "../kernel/fw-emu.c"
 
+/*
+ * Set a break point on this function so that symbols are available to set breakpoints in
+ * the kernel being debugged.
+ */
+static void
+debug_break (void)
+{
+}
+
 static void
 cons_write (const char *buf)
 {
@@ -187,6 +196,7 @@
 
 	ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
 
+	debug_break();
 	asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
 		      :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
 
diff -urN linux-2.4.21-pre1/arch/ia64/config.in linux-2.4.21-pre2/arch/ia64/config.in
--- linux-2.4.21-pre1/arch/ia64/config.in	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/config.in	Wed Dec 18 14:16:26 2002
@@ -51,8 +51,6 @@
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 fi
 
-bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n
-
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
@@ -65,10 +63,6 @@
 
 if [ "$CONFIG_MCKINLEY" = "y" ]; then
 	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
-	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
-	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC
-	fi
 fi
 
 if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
@@ -256,10 +250,10 @@
   mainmenu_option next_comment
   comment 'Simulated drivers'
 
-  bool 'Simulated Ethernet ' CONFIG_SIMETH
-  bool 'Simulated serial driver support' CONFIG_SIM_SERIAL
+  bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+  bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
   if [ "$CONFIG_SCSI" != "n" ]; then
-    bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
+    bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
   fi
   endmenu
 fi
diff -urN linux-2.4.21-pre1/arch/ia64/defconfig linux-2.4.21-pre2/arch/ia64/defconfig
--- linux-2.4.21-pre1/arch/ia64/defconfig	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/defconfig	Wed Dec 18 14:16:26 2002
@@ -35,7 +35,6 @@
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
-CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_IA64_BRL_EMU=y
 # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
 CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -164,6 +163,7 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -402,13 +402,13 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -420,11 +420,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -434,10 +436,9 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-# CONFIG_NET_BROADCOM is not set
 # CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
 CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -502,7 +503,6 @@
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_HCDP=y
 # CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_ACPI is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -563,6 +563,7 @@
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_EFI_RTC=y
@@ -579,6 +580,7 @@
 # CONFIG_AGP_I810 is not set
 # CONFIG_AGP_VIA is not set
 # CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_SWORKS is not set
@@ -626,21 +628,10 @@
 #
 # Radio Adapters
 #
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_GEMTEK is not set
 # CONFIG_RADIO_GEMTEK_PCI is not set
 # CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_MIROPCM20_RDS is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
 
 #
 # File systems
@@ -655,9 +646,11 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 CONFIG_JBD_DEBUG=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
@@ -672,6 +665,9 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -702,6 +698,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -716,7 +713,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -796,9 +792,9 @@
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
@@ -808,6 +804,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -846,6 +843,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -854,6 +852,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -866,6 +865,7 @@
 CONFIG_USB_HIDDEV=y
 CONFIG_USB_KBD=m
 CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -908,39 +908,21 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Bluetooth support
diff -urN linux-2.4.21-pre1/arch/ia64/hp/common/sba_iommu.c linux-2.4.21-pre2/arch/ia64/hp/common/sba_iommu.c
--- linux-2.4.21-pre1/arch/ia64/hp/common/sba_iommu.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/hp/common/sba_iommu.c	Wed Dec 18 14:16:26 2002
@@ -39,8 +39,25 @@
 
 #define PFX "IOC: "
 
+/*
+** This option allows cards capable of 64bit DMA to bypass the IOMMU.  If
+** not defined, all DMA will be 32bit and go through the TLB.
+*/
 #define ALLOW_IOV_BYPASS
+
+/*
+** If a device prefetches beyond the end of a valid pdir entry, it will cause
+** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
+** disconnect on 4k boundaries and prevent such issues.  If the device is
+** particularly agressive, this option will keep the entire pdir valid such
+** that prefetching will hit a valid address.  This could severely impact
+** error containment, and is therefore off by default.  The page that is
+** used for spill-over is poisoned, so that should help debugging somewhat.
+*/
+#undef FULL_VALID_PDIR
+
 #define ENABLE_MARK_CLEAN
+
 /*
 ** The number of debug flags is a clue - this code is fragile.
 */
@@ -52,6 +69,10 @@
 #undef DEBUG_LARGE_SG_ENTRIES
 #undef DEBUG_BYPASS
 
+#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY)
+#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive
+#endif
+
 #define SBA_INLINE	__inline__
 /* #define SBA_INLINE */
 
@@ -196,9 +217,12 @@
 static struct ioc *ioc_list;
 static int reserve_sba_gart = 1;
 
-#define sba_sg_iova(sg) (sg->address)
-#define sba_sg_len(sg) (sg->length)
-#define sba_sg_buffer(sg) (sg->orig_address)
+#define sba_sg_address(sg)	(sg->address ? sg->address : \
+				       page_address((sg)->page) + (sg)->offset)
+
+#ifdef FULL_VALID_PDIR
+static void* prefetch_spill_page;
+#endif
 
 #define GET_IOC(dev)	((struct ioc *) PCI_CONTROLLER(dev)->iommu)
 
@@ -338,10 +362,8 @@
 {
 	while (nents-- > 0) {
 		printk(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg),
-				sba_sg_len(startsg),
-				sba_sg_buffer(startsg));
+				nents, startsg->dma_address,
+				startsg->dma_length, sba_sg_address(startsg));
 		startsg++;
 	}
 }
@@ -352,7 +374,7 @@
 	int the_nents = nents;
 
 	while (the_nents-- > 0) {
-		if (sba_sg_buffer(the_sg) == 0x0UL)
+		if (sba_sg_address(the_sg) == 0x0UL)
 			sba_dump_sg(NULL, startsg, nents);
 		the_sg++;
 	}
@@ -626,7 +648,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -673,6 +695,7 @@
 
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
+#ifndef FULL_VALID_PDIR
 		/*
 		** clear I/O PDIR entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
@@ -680,6 +703,14 @@
 		** been enabled.
 		*/
 		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+		/*
+  		** If we want to maintain the PDIR as valid, put in
+		** the spill page so devices prefetching won't
+		** cause a hard fail.
+		*/
+		ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 	} else {
 		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
 
@@ -689,14 +720,18 @@
 		do {
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
+#ifndef FULL_VALID_PDIR
 			/* clear I/O Pdir entry "valid" bit first */
 			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+			ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM);
 }
 
 /**
@@ -991,32 +1026,28 @@
 
 	dma_sg--;
 	while (nents-- > 0) {
-		int     cnt = sba_sg_len(startsg);
-		sba_sg_len(startsg) = 0;
+		int     cnt = startsg->dma_length;
+		startsg->dma_length = 0;
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
 			printk(" %2d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #endif
 		/*
 		** Look for the start of a new DMA stream
 		*/
-		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
-			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+		if (startsg->dma_address & PIDE_FLAG) {
+			u32 pide = startsg->dma_address & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sba_sg_iova(startsg) = 0;
+			startsg->dma_address = 0;
 			dma_sg++;
-			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+			dma_sg->dma_address = pide | ioc->ibase;
 			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
@@ -1025,13 +1056,13 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+			unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
 			ASSERT(pdirp);
 
 			/* Since multiple Vcontig blocks could make up
 			** one DMA stream, *add* cnt to dma_len.
 			*/
-			sba_sg_len(dma_sg) += cnt;
+			dma_sg->dma_length += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
 			cnt = ROUNDUP(cnt, IOVP_SIZE);
@@ -1091,20 +1122,18 @@
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) (startsg->address); 
+		unsigned long vaddr = (unsigned long) sba_sg_address(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
 		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+		dma_len = vcontig_len = vcontig_end = startsg->length;
 		vcontig_end +=  vaddr;
 		dma_offset = vaddr & ~IOVP_MASK;
 
 		/* PARANOID: clear entries */
-		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
-		sba_sg_iova(startsg) = 0;
-		sba_sg_len(startsg) = 0;
+		startsg->dma_address = startsg->dma_length = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
@@ -1115,6 +1144,9 @@
 
 			startsg++;
 
+			/* PARANOID */
+			startsg->dma_address = startsg->dma_length = 0;
+
 			/* catch brokenness in SCSI layer */
 			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
@@ -1131,15 +1163,12 @@
 			**
 			** append the next transaction?
 			*/
-			vaddr = (unsigned long) sba_sg_iova(startsg);
+			vaddr = (unsigned long) sba_sg_address(startsg);
 			if  (vcontig_end == vaddr)
 			{
-				vcontig_len += sba_sg_len(startsg);
-				vcontig_end += sba_sg_len(startsg);
-				dma_len     += sba_sg_len(startsg);
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				sba_sg_len(startsg) = 0;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
@@ -1158,10 +1187,10 @@
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sba_sg_len(vcontig_sg) = vcontig_len;
+			vcontig_sg->dma_length = vcontig_len;
 
 			vcontig_sg = startsg;
-			vcontig_len = sba_sg_len(startsg);
+			vcontig_len = startsg->length;
 
 			/*
 			** 3) do the entries end/start on page boundaries?
@@ -1171,8 +1200,6 @@
 			{
 				vcontig_end = vcontig_len + vaddr;
 				dma_len += vcontig_len;
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
 				continue;
 			} else {
 				break;
@@ -1184,10 +1211,10 @@
 		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sba_sg_len(vcontig_sg) = vcontig_len;
+		vcontig_sg->dma_length = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
 		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
+		dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
 			| dma_offset);
 		n_mappings++;
@@ -1223,8 +1250,8 @@
 #ifdef ALLOW_IOV_BYPASS
 	if (dev->dma_mask >= ioc->dma_mask) {
 		for (sg = sglist ; filled < nents ; filled++, sg++){
-			sba_sg_buffer(sg) = sba_sg_iova(sg);
-			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+			sg->dma_length = sg->length;
+			sg->dma_address = virt_to_phys(sba_sg_address(sg));
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
@@ -1236,10 +1263,10 @@
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
-		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
-						sba_sg_buffer(sglist),
-						sba_sg_len(sglist), direction);
+		sglist->dma_length = sglist->length;
+		sglist->dma_address = sba_map_single(dev,
+		                                     sba_sg_address(sglist),
+		                                     sglist->length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
@@ -1318,7 +1345,7 @@
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1333,10 +1360,10 @@
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-	while (sba_sg_len(sglist) && nents--) {
+	while (nents && sglist->dma_length) {
 
-		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_len(sglist), direction);
+		sba_unmap_single(dev, sglist->dma_address,
+		                 sglist->dma_length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1344,9 +1371,10 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length + IOVP_SIZE - 1) >> PAGE_SHIFT;
 #endif
-		++sglist;
+		sglist++;
+		nents--;
 	}
 
 	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
@@ -1359,12 +1387,6 @@
 
 }
 
-unsigned long
-sba_dma_address (struct scatterlist *sg)
-{
-	return ((unsigned long)sba_sg_iova(sg));
-}
-
 int
 sba_dma_supported (struct pci_dev *dev, u64 mask)
 {
@@ -1384,6 +1406,9 @@
 	int iov_order, tcnfg;
 	int agp_found = 0;
 	struct pci_dev *device;
+#ifdef FULL_VALID_PDIR
+	unsigned long index;
+#endif
 
 	/*
 	** Firmware programs the base and size of a "safe IOVA space"
@@ -1481,7 +1506,7 @@
 	** Clear I/O TLB of any possible entries.
 	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM);
+	WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM);
 
 	/*
 	** If an AGP device is present, only use half of the IOV space
@@ -1499,6 +1524,34 @@
 		ioc->pdir_size /= 2;
 		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
 	}
+#ifdef FULL_VALID_PDIR
+	/*
+  	** Check to see if the spill page has been allocated, we don't need more than
+	** one across multiple SBAs.
+	*/
+	if (!prefetch_spill_page) {
+		char *spill_poison = "SBAIOMMU POISON";
+		int poison_size = 16;
+		void *poison_addr;
+									
+		prefetch_spill_page = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE));
+		if (!prefetch_spill_page)
+			panic(PFX "Couldn't allocate PDIR spill page\n");
+
+		poison_addr = prefetch_spill_page;
+		for (; (u64)poison_addr < (u64)prefetch_spill_page + IOVP_SIZE ; poison_addr += poison_size)
+			(void)memcpy(poison_addr,spill_poison,poison_size);
+
+		prefetch_spill_page = (void *)virt_to_phys(prefetch_spill_page);
+
+		DBG_INIT("%s() prefetch spill addr: %p\n", __FUNCTION__, prefetch_spill_page);
+	}
+	/*
+  	** Set all the PDIR entries valid w/ the spill page as the target
+	*/
+	for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++)
+		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 }
 
 static void __init
@@ -1525,6 +1578,11 @@
 	ioc->res_map[0] = 0x1;
 	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
 #endif
+#ifdef FULL_VALID_PDIR
+	/* Mark the last resource used so we don't prefetch beyond IOVA space */
+	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */
+	ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 
 	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
 		 ioc->res_size, (void *) ioc->res_map);
@@ -1608,15 +1666,23 @@
 				(info->init)(ioc);
 		}
 	}
-	if (!ioc->name)
-		ioc->name = "Unknown";
+
+	if (!ioc->name) {
+		ioc->name = kmalloc(24, GFP_KERNEL);
+		if (ioc->name)
+			sprintf(ioc->name, "Unknown (%04x:%04x)",
+				ioc->func_id & 0xFFFF,
+				(ioc->func_id >> 16) & 0xFFFF);
+		else
+			ioc->name = "Unknown";
+	}
 
 	ioc_iova_init(ioc);
 	ioc_resource_init(ioc);
 	ioc_sac_init(ioc);
 
 	printk(KERN_INFO PFX
-		"Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
 		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
 		hpa, ioc->iov_size >> 20, ioc->ibase);
 
@@ -1861,7 +1927,6 @@
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
-EXPORT_SYMBOL(sba_dma_address);
 EXPORT_SYMBOL(sba_dma_supported);
 EXPORT_SYMBOL(sba_alloc_consistent);
 EXPORT_SYMBOL(sba_free_consistent);
diff -urN linux-2.4.21-pre1/arch/ia64/hp/sim/Makefile linux-2.4.21-pre2/arch/ia64/hp/sim/Makefile
--- linux-2.4.21-pre1/arch/ia64/hp/sim/Makefile	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/hp/sim/Makefile	Wed Dec 18 14:16:26 2002
@@ -1,6 +1,8 @@
 #
 # ia64/platform/hp/sim/Makefile
 #
+# Copyright (C) 2002 Hewlett-Packard Co.
+#	David Mosberger-Tang <davidm@hpl.hp.com>
 # Copyright (C) 1999 Silicon Graphics, Inc.
 # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
 #
diff -urN linux-2.4.21-pre1/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.21-pre2/arch/ia64/hp/zx1/hpzx1_misc.c
--- linux-2.4.21-pre1/arch/ia64/hp/zx1/hpzx1_misc.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/hp/zx1/hpzx1_misc.c	Wed Dec 18 14:16:26 2002
@@ -17,8 +17,6 @@
 #include <asm/dma.h>
 #include <asm/iosapic.h>
 
-extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
-
 #define PFX "hpzx1: "
 
 static int hpzx1_devices;
@@ -252,40 +250,8 @@
 	 * HWP0003: AGP LBA device
 	 */
 	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-#ifdef CONFIG_IA64_HP_PROTO
-	if (hpzx1_devices) {
-#endif
 	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
 	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
-
-#ifdef CONFIG_IA64_HP_PROTO
-	}
-
-#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
-	/*
-	 * Early protos don't have bridges in the ACPI namespace, so
-	 * if we didn't find anything, add the things we know are
-	 * there.
-	 */
-	if (hpzx1_devices == 0) {
-		u64 hpa, csr_base;
-
-		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x2000);
-		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
-					    0x1000);
-
-			csr_base = 0xfed24000UL;
-			iounmap(hpa);
-			hpa = (u64) ioremap(csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
-					    0x1000);
-		}
-		iounmap(hpa);
-	}
-#endif
 }
 
 extern void sba_init(void);
diff -urN linux-2.4.21-pre1/arch/ia64/ia32/ia32_signal.c linux-2.4.21-pre2/arch/ia64/ia32/ia32_signal.c
--- linux-2.4.21-pre1/arch/ia64/ia32/ia32_signal.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/ia64/ia32/ia32_signal.c	Wed Dec 18 14:16:26 2002
@@ -39,6 +39,16 @@
 #define __IA32_NR_sigreturn            119
 #define __IA32_NR_rt_sigreturn         173
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 struct sigframe_ia32
 {
        int pretcode;
@@ -143,6 +153,304 @@
 	return err;
 }
 
+
+/*
+ *  SAVE and RESTORE of ia32 fpstate info, from ia64 current state
+ *  Used in exception handler to pass the fpstate to the user, and restore
+ *  the fpstate while returning from the exception handler.
+ *
+ *    fpstate info and their mapping to IA64 regs:
+ *    fpstate    REG(BITS)      Attribute    Comments
+ *    cw         ar.fcr(0:12)                with bits 7 and 6 not used
+ *    sw         ar.fsr(0:15)
+ *    tag        ar.fsr(16:31)               with odd numbered bits not used
+ *                                           (read returns 0, writes ignored)
+ *    ipoff      ar.fir(0:31)
+ *    cssel      ar.fir(32:47)
+ *    dataoff    ar.fdr(0:31)
+ *    datasel    ar.fdr(32:47)
+ *
+ *    _st[(0+TOS)%8]   f8
+ *    _st[(1+TOS)%8]   f9                    (f8, f9 from ptregs)
+ *      : :            :                     (f10..f15 from live reg)
+ *      : :            :
+ *    _st[(7+TOS)%8]   f15                   TOS=sw.top(bits11:13)
+ *
+ *    status     Same as sw     RO
+ *    magic      0                           as X86_FXSR_MAGIC in ia32
+ *    mxcsr      Bits(7:15)=ar.fcr(39:47)
+ *               Bits(0:5) =ar.fsr(32:37)    with bit 6 reserved
+ *    _xmm[0..7] f16..f31                    (live registers)
+ *                                           with _xmm[0]
+ *                                             Bit(64:127)=f17(0:63)
+ *                                             Bit(0:63)=f16(0:63)
+ *    All other fields unused...
+ */
+
+#define __ldfe(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldfe %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __ldf8(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldf8 %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __stfe(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+#define __stf8(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+static int
+save_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	unsigned long new_fsr;
+	unsigned long num128[2];
+	unsigned long mxcsr=0;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	/* Readin fsr, fcr, fir, fdr and copy onto fpstate */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+	/*
+	 * We need to clear the exception state before calling the signal handler. Clear
+	 * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex
+	 * instruction.
+	 */
+	new_fsr = fsr & ~0x80ff;
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(new_fsr));
+
+	__put_user(fcr & 0xffff, &save->cw);
+	__put_user(fsr & 0xffff, &save->sw);
+	__put_user((fsr>>16) & 0xffff, &save->tag);
+	__put_user(fir, &save->ipoff);
+	__put_user((fir>>32) & 0xffff, &save->cssel);
+	__put_user(fdr, &save->dataoff);
+	__put_user((fdr>>32) & 0xffff, &save->datasel);
+	__put_user(fsr & 0xffff, &save->status);
+
+	mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	__put_user( 0, &save->magic); //#define X86_FXSR_MAGIC   0x0000
+
+	/*
+	 * save f8 and f9  from pt_regs
+	 * save f10..f15 from live register set
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	ptp = ia64_task_regs(tsk);
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+	ia64f2ia32f(fpregp, &ptp->f8);
+	copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	ia64f2ia32f(fpregp, &ptp->f9);
+	copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stfe(fpregp, 10);
+	copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 11);
+	copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 12);
+	copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 13);
+	copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 14);
+	copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 15);
+	copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stf8(&num128[0], 16);
+	__stf8(&num128[1], 17);
+	copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 18);
+	__stf8(&num128[1], 19);
+	copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 20);
+	__stf8(&num128[1], 21);
+	copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 22);
+	__stf8(&num128[1], 23);
+	copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 24);
+	__stf8(&num128[1], 25);
+	copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 26);
+	__stf8(&num128[1], 27);
+	copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 28);
+	__stf8(&num128[1], 29);
+	copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 30);
+	__stf8(&num128[1], 31);
+	copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32));
+	return 0;
+}
+
+static int
+restore_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	unsigned int lo, hi;
+	unsigned long num128[2];
+	unsigned long num64, mxcsr;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	/*
+	 * Updating fsr, fcr, fir, fdr.
+	 * Just a bit more complicated than save.
+	 * - Need to make sure that we dont write any value other than the
+	 *   specific fpstate info
+	 * - Need to make sure that the untouched part of frs, fdr, fir, fcr
+	 *   should remain same while writing.
+	 * So, we do a read, change specific fields and write.
+	 */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	/* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->cw);
+	num64 = mxcsr & 0xff10;
+	num64 = (num64 << 32) | (lo & 0x1f3f);
+	fcr = (fcr & (~0xff1000001f3f)) | num64;
+
+	/* setting bits 0..31 with sw and tag and 32..37 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->sw);
+	/* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */
+	if ( !(lo & 0x7f) )
+		lo &= (~0x8080);
+	__get_user(hi, (unsigned int *)&save->tag);
+	num64 = mxcsr & 0x3f;
+	num64 = (num64 << 16) | (hi & 0xffff);
+	num64 = (num64 << 16) | (lo & 0xffff);
+	fsr = (fsr & (~0x3fffffffff)) | num64;
+
+	/* setting bits 0..47 with cssel and ipoff */
+	__get_user(lo, (unsigned int *)&save->ipoff);
+	__get_user(hi, (unsigned int *)&save->cssel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fir = (fir & (~0xffffffffffff)) | num64;
+
+	/* setting bits 0..47 with datasel and dataoff */
+	__get_user(lo, (unsigned int *)&save->dataoff);
+	__get_user(hi, (unsigned int *)&save->datasel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fdr = (fdr & (~0xffffffffffff)) | num64;
+
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(fsr));
+	asm volatile ( "mov ar.fcr=%0;" :: "r"(fcr));
+	asm volatile ( "mov ar.fir=%0;" :: "r"(fir));
+	asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr));
+
+	/*
+	 * restore f8, f9 onto pt_regs
+	 * restore f10..f15 onto live registers
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+
+	ptp = ia64_task_regs(tsk);
+	copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f8, fpregp);
+	copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f9, fpregp);
+
+	copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(10, fpregp);
+	copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(11, fpregp);
+	copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(12, fpregp);
+	copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(13, fpregp);
+	copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(14, fpregp);
+	copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(15, fpregp);
+
+	copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32));
+	__ldf8(16, &num128[0]);
+	__ldf8(17, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32));
+	__ldf8(18, &num128[0]);
+	__ldf8(19, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32));
+	__ldf8(20, &num128[0]);
+	__ldf8(21, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32));
+	__ldf8(22, &num128[0]);
+	__ldf8(23, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32));
+	__ldf8(24, &num128[0]);
+	__ldf8(25, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32));
+	__ldf8(26, &num128[0]);
+	__ldf8(27, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32));
+	__ldf8(28, &num128[0]);
+	__ldf8(29, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32));
+	__ldf8(30, &num128[0]);
+	__ldf8(31, &num128[1]);
+	return 0;
+}
+
 static inline void
 sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
 {
@@ -371,6 +679,9 @@
 	int  err = 0;
 	unsigned long flag;
 
+	if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc)))
+		return -EFAULT;
+
 	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
 	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
 	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
@@ -397,6 +708,11 @@
 	err |= __put_user(regs->r12, &sc->esp_at_signal);
 	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
+	if ( save_ia32_fpstate_live(fpstate) < 0 )
+		err = -EFAULT;
+	else
+		err |= __put_user((u32)(u64)fpstate, &sc->fpstate);
+
 #if 0
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
@@ -418,6 +734,9 @@
 {
 	unsigned int err = 0;
 
+	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
+		return(-EFAULT);
+
 #define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
 #define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
@@ -477,6 +796,16 @@
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
 	}
 
+	{
+		struct _fpstate_ia32 *buf = NULL;
+		u32    fpstate_ptr;
+		err |= get_user(fpstate_ptr, &(sc->fpstate));
+		buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr;
+		if (buf) {
+			err |= restore_ia32_fpstate_live(buf);
+		}
+	}
+
 #if 0
 	{
 		struct _fpstate * buf;
diff -urN linux-2.4.21-pre1/arch/ia64/ia32/sys_ia32.c linux-2.4.21-pre2/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.21-pre1/arch/ia64/ia32/sys_ia32.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/ia64/ia32/sys_ia32.c	Wed Dec 18 14:16:26 2002
@@ -2118,8 +2118,8 @@
 };
 
 struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
+	u32 msgp;
+	s32 msgtyp;
 };
 
 #define SEMOP		 1
@@ -2843,20 +2843,6 @@
 	}
 }
 
-static inline void
-ia32f2ia64f (void *dst, void *src)
-{
-	asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory");
-	return;
-}
-
-static inline void
-ia64f2ia32f (void *dst, void *src)
-{
-	asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst),  "r"(src) : "memory");
-	return;
-}
-
 static void
 put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
 	   int tos)
@@ -2913,57 +2899,152 @@
 }
 
 static int
-save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
 	int i, tos;
 
 	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-		return -EIO;
-	__put_user(tsk->thread.fcr, &save->cw);
-	__put_user(tsk->thread.fsr, &save->sw);
-	__put_user(tsk->thread.fsr >> 32, &save->tag);
-	__put_user(tsk->thread.fir, &save->ipoff);
-	__put_user(__USER_CS, &save->cssel);
-	__put_user(tsk->thread.fdr, &save->dataoff);
-	__put_user(__USER_DS, &save->datasel);
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		put_fpreg(i, &save->_st[i], ptp, swp, tos);
+		put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
 	return 0;
 }
 
 static int
-restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
-	int i, tos, ret;
-	int fsrlo, fsrhi;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
 
 	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-		return(-EIO);
-	ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
-	ret |= __get_user(fsrlo, (unsigned int *)&save->sw);
-	ret |= __get_user(fsrhi, (unsigned int *)&save->tag);
-	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
-	ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
-	ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return ret ? -EFAULT : 0;
+		get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+	return 0;
+}
+
+static int
+save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned long mxcsr=0;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
+        /*
+         *  Stack frames start with 16-bytes of temp space
+         */
+        swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+        ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+        for (i = 0; i < 8; i++)
+		put_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	for (i = 0; i < 8; i++) {
+		memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long));
+		memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long));
+		copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32));
+	}
+	return 0;
+}
+
+static int
+restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
+	int mxcsr;
+	unsigned long num64;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+	for (i = 0; i < 8; i++)
+	get_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	num64 = mxcsr & 0xff10;
+	tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32);
+	num64 = mxcsr & 0x3f;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32);
+
+	for (i = 0; i < 8; i++) {
+		copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32));
+		memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long));
+		memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long));
+	}
+	return 0;
 }
 
 extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
@@ -3075,11 +3156,19 @@
 		break;
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_GETFPXREGS:
+		ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_SETFPXREGS:
+		ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/acpi.c linux-2.4.21-pre2/arch/ia64/kernel/acpi.c
--- linux-2.4.21-pre1/arch/ia64/kernel/acpi.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/acpi.c	Wed Dec 18 14:16:26 2002
@@ -102,8 +102,6 @@
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
-# elif defined (CONFIG_IA64_HP_ZX1)
-	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
@@ -112,33 +110,7 @@
 
 #ifdef CONFIG_ACPI
 
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, acpi_buffer *buf)
-{
-	acpi_status result;
-	buf->length = 0;
-	buf->pointer = NULL;
-
-	result = acpi_get_current_resources(obj, buf);
-	if (result != AE_BUFFER_OVERFLOW)
-		return result;
-	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
-	if (!buf->pointer)
-		return -ENOMEM;
-
-	return acpi_get_current_resources(obj, buf);
-}
-
-acpi_resource *
+static acpi_resource *
 acpi_get_crs_next (acpi_buffer *buf, int *offset)
 {
 	acpi_resource *res;
@@ -146,12 +118,12 @@
 	if (*offset >= buf->length)
 		return NULL;
 
-	res = buf->pointer + *offset;
+	res = (acpi_resource *)((char *) buf->pointer + *offset);
 	*offset += res->length;
 	return res;
 }
 
-acpi_resource_data *
+static acpi_resource_data *
 acpi_get_crs_type (acpi_buffer *buf, int *offset, int type)
 {
 	for (;;) {
@@ -163,12 +135,6 @@
 	}
 }
 
-void
-acpi_dispose_crs (acpi_buffer *buf)
-{
-	kfree(buf->pointer);
-}
-
 static void
 acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra)
 {
@@ -210,6 +176,9 @@
 					return;
 				}
 				break;
+			case ACPI_RSTYPE_END_TAG:
+				return;
+				break;
 		}
 	}
 }
@@ -218,13 +187,14 @@
 acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
 {
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 
 	*base = 0;
 	*length = 0;
 	*tra = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
@@ -232,7 +202,7 @@
 
 	acpi_get_crs_addr(&buf, type, base, length, tra);
 
-	acpi_dispose_crs(&buf);
+	acpi_os_free(buf.pointer);
 
 	return AE_OK;
 }
@@ -254,7 +224,8 @@
 {
 	int i, offset = 0;
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 	acpi_resource_vendor *res;
 	acpi_hp_vendor_long *hp_res;
 	efi_guid_t vendor_guid;
@@ -262,42 +233,41 @@
 	*csr_base = 0;
 	*csr_length = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
 	}
 
+	status = AE_NOT_FOUND;
 	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
 	if (!res) {
 		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
+		goto out;
 	}
 
+	status = AE_TYPE; /* Revisit error? */
 	hp_res = (acpi_hp_vendor_long *)(res->reserved);
 
 	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
 		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
 	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
 	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
 		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
+		goto out;
 	}
 
-	acpi_dispose_crs(&buf);
-
-	return AE_OK;
+	/* It's probably unaligned, so use memcpy */
+	memcpy(csr_base, hp_res->csr_base, 8);
+	memcpy(csr_length, hp_res->csr_length, 8);
+	status = AE_OK;
+
+ out:
+	acpi_os_free(buf.pointer);
+	return status;
 }
 #endif /* CONFIG_ACPI */
 
@@ -368,6 +338,7 @@
 acpi_parse_lsapic (acpi_table_entry_header *header)
 {
 	struct acpi_table_lsapic *lsapic;
+	int phys_id;
 
 	lsapic = (struct acpi_table_lsapic *) header;
 	if (!lsapic)
@@ -375,13 +346,21 @@
 
 	acpi_table_print_madt_entry(header);
 
-	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+	phys_id = (lsapic->id << 8) | lsapic->eid;
+
+	if (total_cpus == NR_CPUS) {
+		printk(KERN_ERR PREFIX "Ignoring CPU (0x%04x) (NR_CPUS == %d)\n",
+			phys_id, NR_CPUS);
+		return 0;
+	}
+
+	printk("CPU %d (0x%04x)", total_cpus, phys_id);
 
 	if (lsapic->flags.enabled) {
 		available_cpus++;
 		printk(" enabled");
 #ifdef CONFIG_SMP
-		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+		smp_boot_data.cpu_phys_id[total_cpus] = phys_id;
 		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/efi.c linux-2.4.21-pre2/arch/ia64/kernel/efi.c
--- linux-2.4.21-pre1/arch/ia64/kernel/efi.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/efi.c	Wed Dec 18 14:16:26 2002
@@ -51,66 +51,156 @@
 
 static unsigned long mem_limit = ~0UL;
 
-static efi_status_t
-phys_get_time (efi_time_t *tm, efi_time_cap_t *tc)
-{
-	return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc));
-}
-
-static efi_status_t
-phys_set_time (efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_time), __pa(tm));
-}
+#define efi_call_virt(f, args...)	(*(f))(args)
 
-static efi_status_t
-phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending),
-			     __pa(tm));
-}
-
-static efi_status_t
-phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm));
-}
-
-static efi_status_t
-phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-		   unsigned long *data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr),
-			     __pa(data_size), __pa(data));
-}
-
-static efi_status_t
-phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
-{
-	return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name),
-			     __pa(vendor));
-}
-
-static efi_status_t
-phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
-		   unsigned long data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr,
-			     data_size, __pa(data));
-}
-
-static efi_status_t
-phys_get_next_high_mono_count (u64 *count)
-{
-	return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count));
-}
-
-static void
-phys_reset_system (int reset_type, efi_status_t status,
-		   unsigned long data_size, efi_char16_t *data)
-{
-	efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data));
-}
+#define STUB_GET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)						\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm),	\
+				adjust_arg(tc));						\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_set_time (efi_time_t *tm)								\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)		\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),	\
+				adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)					\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),	\
+				enabled, adjust_arg(tm));					\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,		\
+		       unsigned long *data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable),	\
+				adjust_arg(name), adjust_arg(vendor), adjust_arg(attr),	\
+				adjust_arg(data_size), adjust_arg(data));		\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)	\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable),	\
+				adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,		\
+		       unsigned long data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable),	\
+				adjust_arg(name), adjust_arg(vendor), attr, data_size,	\
+				adjust_arg(data));					\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)					\
+static efi_status_t										\
+prefix##_get_next_high_mono_count (u64 *count)							\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)				\
+				__va(runtime->get_next_high_mono_count), adjust_arg(count));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_RESET_SYSTEM(prefix, adjust_arg)					\
+static void									\
+prefix##_reset_system (int reset_type, efi_status_t status,			\
+		       unsigned long data_size, efi_char16_t *data)		\
+{										\
+	struct ia64_fpreg fr[6];						\
+										\
+	ia64_save_scratch_fpregs(fr);						\
+	efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system),	\
+			  reset_type, status, data_size, adjust_arg(data));	\
+	/* should not return, but just in case... */				\
+	ia64_load_scratch_fpregs(fr);						\
+}
+
+STUB_GET_TIME(phys, __pa)
+STUB_SET_TIME(phys, __pa)
+STUB_GET_WAKEUP_TIME(phys, __pa)
+STUB_SET_WAKEUP_TIME(phys, __pa)
+STUB_GET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_VARIABLE(phys, __pa)
+STUB_SET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa)
+STUB_RESET_SYSTEM(phys, __pa)
+
+STUB_GET_TIME(virt, )
+STUB_SET_TIME(virt, )
+STUB_GET_WAKEUP_TIME(virt, )
+STUB_SET_WAKEUP_TIME(virt, )
+STUB_GET_VARIABLE(virt, )
+STUB_GET_NEXT_VARIABLE(virt, )
+STUB_SET_VARIABLE(virt, )
+STUB_GET_NEXT_HIGH_MONO_COUNT(virt, )
+STUB_RESET_SYSTEM(virt, )
 
 void
 efi_gettimeofday (struct timeval *tv)
@@ -207,7 +297,7 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p, *q;
+	void *efi_map_start, *efi_map_end, *p, *q, *r;
 	efi_memory_desc_t *md, *check_md;
 	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
@@ -252,11 +342,10 @@
 
 			if (!(first_non_wb_addr > granule_addr))
 				continue;	/* couldn't find enough contiguous memory */
-		}
-
-		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
 
-		trim_top(md, first_non_wb_addr);
+			for (r = p; r < q; r += efi_desc_size)
+				trim_top(r, first_non_wb_addr);
+		}
 
 		if (is_available_memory(md)) {
 			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
@@ -540,23 +629,22 @@
 			       efi_desc_size, ia64_boot_param->efi_memdesc_version,
 			       ia64_boot_param->efi_memmap);
 	if (status != EFI_SUCCESS) {
-		printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status);
+		printk("Warning: unable to switch EFI into virtual mode (status=0x%lx)\n", status);
 		return;
 	}
 
 	/*
-	 * Now that EFI is in virtual mode, we arrange for EFI functions to be
-	 * called directly:
+	 * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
 	 */
-	efi.get_time = __va(runtime->get_time);
-	efi.set_time = __va(runtime->set_time);
-	efi.get_wakeup_time = __va(runtime->get_wakeup_time);
-	efi.set_wakeup_time = __va(runtime->set_wakeup_time);
-	efi.get_variable = __va(runtime->get_variable);
-	efi.get_next_variable = __va(runtime->get_next_variable);
-	efi.set_variable = __va(runtime->set_variable);
-	efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count);
-	efi.reset_system = __va(runtime->reset_system);
+	efi.get_time = virt_get_time;
+	efi.set_time = virt_set_time;
+	efi.get_wakeup_time = virt_get_wakeup_time;
+	efi.set_wakeup_time = virt_set_wakeup_time;
+	efi.get_variable = virt_get_variable;
+	efi.get_next_variable = virt_get_next_variable;
+	efi.set_variable = virt_set_variable;
+	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
+	efi.reset_system = virt_reset_system;
 }
 
 /*
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/entry.S linux-2.4.21-pre2/arch/ia64/kernel/entry.S
--- linux-2.4.21-pre1/arch/ia64/kernel/entry.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/entry.S	Wed Dec 18 14:16:26 2002
@@ -1109,7 +1109,7 @@
 	data8 sys_mlock
 	data8 sys_mlockall
 	data8 sys_mprotect			// 1155
-	data8 sys_mremap
+	data8 ia64_mremap
 	data8 sys_msync
 	data8 sys_munlock
 	data8 sys_munlockall
@@ -1170,18 +1170,18 @@
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
 	data8 sys_readahead
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1220
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1225
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_setxattr
+	data8 sys_lsetxattr
+	data8 sys_fsetxattr
+	data8 sys_getxattr			// 1220
+	data8 sys_lgetxattr
+	data8 sys_fgetxattr
+	data8 sys_listxattr
+	data8 sys_llistxattr
+	data8 sys_flistxattr			// 1225
+	data8 sys_removexattr
+	data8 sys_lremovexattr
+	data8 sys_fremovexattr
 	data8 sys_tkill
 	data8 ia64_ni_syscall			// 1230
 	data8 ia64_ni_syscall
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/fw-emu.c linux-2.4.21-pre2/arch/ia64/kernel/fw-emu.c
--- linux-2.4.21-pre1/arch/ia64/kernel/fw-emu.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/fw-emu.c	Wed Dec 18 14:16:26 2002
@@ -2,7 +2,7 @@
  * PAL & SAL emulation.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * For the HP simulator, this file gets include in boot/bootloader.c.
  * For SoftSDV, this file gets included in sys_softsdv.c.
@@ -19,10 +19,14 @@
 #include <asm/sal.h>
 
 #define MB	(1024*1024UL)
-#define GB	(1024*MB)
-#define TB	(1024*GB)
 
-#define NUM_MEM_DESCS	4
+#define SIMPLE_MEMMAP	1
+
+#if SIMPLE_MEMMAP
+# define NUM_MEM_DESCS	4
+#else
+# define NUM_MEM_DESCS	16
+#endif
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -381,6 +385,17 @@
 	struct ia64_boot_param *bp;
 	unsigned char checksum = 0;
 	char *cp, *cmd_line;
+	int i = 0;
+#	define MAKE_MD(typ, attr, start, end)		\
+	do {						\
+		md = efi_memmap + i++;			\
+		md->type = typ;				\
+		md->pad = 0;				\
+		md->phys_addr = start;			\
+		md->virt_addr = 0;			\
+		md->num_pages = (end - start) >> 12;	\
+		md->attribute = attr;			\
+	} while (0)
 
 	memset(fw_mem, 0, sizeof(fw_mem));
 
@@ -466,41 +481,30 @@
 
 	sal_systab->checksum = -checksum;
 
+#if SIMPLE_MEMMAP
 	/* simulate free memory at physical address zero */
-	md = &efi_memmap[0];
-	md->type = EFI_BOOT_SERVICES_DATA;
-	md->pad = 0;
-	md->phys_addr = 0*MB;
-	md->virt_addr = 0;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* fill in a memory descriptor: */
-	md = &efi_memmap[1];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 2*MB;
-	md->virt_addr = 0;
-	md->num_pages = (128*MB) >> 12;	/* 128MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
-
-	/* descriptor for firmware emulator: */
-	md = &efi_memmap[2];
-	md->type = EFI_PAL_CODE;
-	md->pad = 0;
-	md->phys_addr = 1*MB;
-	md->virt_addr = 1*MB;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* descriptor for high memory (>4TB): */
-	md = &efi_memmap[3];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 4*TB;
-	md->virt_addr = 0;
-	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
+	MAKE_MD(EFI_BOOT_SERVICES_DATA,		EFI_MEMORY_WB,    0*MB,    1*MB);
+	MAKE_MD(EFI_PAL_CODE,			EFI_MEMORY_WB,    1*MB,    2*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB,    2*MB,  130*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB, 4096*MB, 4128*MB);
+#else
+	MAKE_MD( 4,		   0x9, 0x0000000000000000, 0x0000000000001000);
+	MAKE_MD( 7,		   0x9, 0x0000000000001000, 0x000000000008a000);
+	MAKE_MD( 4,		   0x9, 0x000000000008a000, 0x00000000000a0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000);
+	MAKE_MD( 7,		   0x9, 0x0000000000100000, 0x0000000004400000);
+	MAKE_MD( 2,		   0x9, 0x0000000004400000, 0x0000000004be5000);
+	MAKE_MD( 7,		   0x9, 0x0000000004be5000, 0x000000007f77e000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000);
+	MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000);
+	MAKE_MD( 7,		   0x9, 0x000000007fc3a000, 0x000000007fea0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000);
+	MAKE_MD( 7,		   0x9, 0x000000007fea8000, 0x000000007feab000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000);
+	MAKE_MD( 7,		   0x9, 0x00000000ff400000, 0x0000000104000000);
+#endif
 
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/gate.S linux-2.4.21-pre2/arch/ia64/kernel/gate.S
--- linux-2.4.21-pre1/arch/ia64/kernel/gate.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/gate.S	Wed Dec 18 14:16:26 2002
@@ -2,7 +2,7 @@
  * This file contains the code that gets mapped at the upper end of each task's text
  * region.  For now, it contains the signal trampoline code only.
  *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2002 Hewlett-Packard Co
  * 	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -135,7 +135,7 @@
 	;;
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
-(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14 and r16)
+(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14-r18, f6 & f7)
 	;;
 back_from_restore_rbs:
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
@@ -189,20 +189,69 @@
 	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 	.body
 restore_rbs:
+	// On input:
+	//	r14 = bsp1 (bsp at the time of return from signal handler)
+	//	r15 = bsp0 (bsp at the time the signal occurred)
+	//
+	// Here, we need to calculate bspstore0, the value that ar.bspstore needs
+	// to be set to, based on bsp0 and the size of the dirty partition on
+	// the alternate stack (sc_loadrs >> 16).  This can be done with the
+	// following algorithm:
+	//
+	//  bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
+	//
+	// This is what the code below does.
+	//
 	alloc r2=ar.pfs,0,0,0,0			// alloc null frame
 	adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+	adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
-	ld8 r14=[r16]
-	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
+	ld8 r17=[r16]
+	ld8 r16=[r18]			// get new rnat
+	extr.u r18=r15,3,6	// r18 <- rse_slot_num(bsp0)
 	;;
-	mov ar.rsc=r14				// put RSE into enforced lazy mode
-	ld8 r14=[r16]				// get new rnat
+	mov ar.rsc=r17			// put RSE into enforced lazy mode
+	shr.u r17=r17,16
 	;;
-	loadrs					// restore dirty partition
+	sub r14=r14,r17		// r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
+	shr.u r17=r17,3		// r17 <- (sc_loadrs >> 19)
+	;;
+	loadrs			// restore dirty partition
+	extr.u r14=r14,3,6	// r14 <- rse_slot_num(bspstore1)
+	;;
+	add r14=r14,r17		// r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
+	;;
+	shr.u r14=r14,6		// r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
+	;;
+	sub r14=r14,r17		// r14 <- -rse_num_regs(bspstore1, bsp1)
+	movl r17=0x8208208208208209
+	;;
+	add r18=r18,r14		// r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
+	setf.sig f7=r17
+	cmp.lt p7,p0=r14,r0	// p7 <- (r14 < 0)?
+	;;
+(p7)	adds r18=-62,r18	// delta -= 62
+	;;
+	setf.sig f6=r18
+	;;
+	xmpy.h f6=f6,f7
+	;;
+	getf.sig r17=f6
+	;;
+	add r17=r17,r18
+	shr r18=r18,63
+	;;
+	shr r17=r17,5
+	;;
+	sub r17=r17,r18		// r17 = delta/63
+	;;
+	add r17=r14,r17		// r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
+	;;
+	shladd r15=r17,3,r15	// r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
 	;;
 	mov ar.bspstore=r15			// switch back to old register backing store area
 	;;
-	mov ar.rnat=r14				// restore RNaT
+	mov ar.rnat=r16				// restore RNaT
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
 	br.cond.sptk back_from_restore_rbs
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/head.S linux-2.4.21-pre2/arch/ia64/kernel/head.S
--- linux-2.4.21-pre1/arch/ia64/kernel/head.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/head.S	Wed Dec 18 14:16:26 2002
@@ -13,6 +13,8 @@
  * Copyright (C) 1999 Intel Corp.
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
+ * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
+ *   -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
  */
 
 #include <linux/config.h>
@@ -262,302 +264,297 @@
 END(ia64_load_debug_regs)
 
 GLOBAL_ENTRY(__ia64_save_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
+	alloc r2=ar.pfs,1,4,0,0
+	adds loc0=96*16-16,in0
+	adds loc1=96*16-16-128,in0
 	;;
-	stf.spill.nta [in0]=f32,32
-	stf.spill.nta [ r3]=f33,32
+	stf.spill.nta [loc0]=f127,-256
+	stf.spill.nta [loc1]=f119,-256
 	;;
-	stf.spill.nta [in0]=f34,32
-	stf.spill.nta [ r3]=f35,32
+	stf.spill.nta [loc0]=f111,-256
+	stf.spill.nta [loc1]=f103,-256
 	;;
-	stf.spill.nta [in0]=f36,32
-	stf.spill.nta [ r3]=f37,32
+	stf.spill.nta [loc0]=f95,-256
+	stf.spill.nta [loc1]=f87,-256
 	;;
-	stf.spill.nta [in0]=f38,32
-	stf.spill.nta [ r3]=f39,32
+	stf.spill.nta [loc0]=f79,-256
+	stf.spill.nta [loc1]=f71,-256
 	;;
-	stf.spill.nta [in0]=f40,32
-	stf.spill.nta [ r3]=f41,32
+	stf.spill.nta [loc0]=f63,-256
+	stf.spill.nta [loc1]=f55,-256
+	adds loc2=96*16-32,in0
 	;;
-	stf.spill.nta [in0]=f42,32
-	stf.spill.nta [ r3]=f43,32
+	stf.spill.nta [loc0]=f47,-256
+	stf.spill.nta [loc1]=f39,-256
+	adds loc3=96*16-32-128,in0
 	;;
-	stf.spill.nta [in0]=f44,32
-	stf.spill.nta [ r3]=f45,32
+	stf.spill.nta [loc2]=f126,-256
+	stf.spill.nta [loc3]=f118,-256
 	;;
-	stf.spill.nta [in0]=f46,32
-	stf.spill.nta [ r3]=f47,32
+	stf.spill.nta [loc2]=f110,-256
+	stf.spill.nta [loc3]=f102,-256
 	;;
-	stf.spill.nta [in0]=f48,32
-	stf.spill.nta [ r3]=f49,32
+	stf.spill.nta [loc2]=f94,-256
+	stf.spill.nta [loc3]=f86,-256
 	;;
-	stf.spill.nta [in0]=f50,32
-	stf.spill.nta [ r3]=f51,32
+	stf.spill.nta [loc2]=f78,-256
+	stf.spill.nta [loc3]=f70,-256
 	;;
-	stf.spill.nta [in0]=f52,32
-	stf.spill.nta [ r3]=f53,32
+	stf.spill.nta [loc2]=f62,-256
+	stf.spill.nta [loc3]=f54,-256
+	adds loc0=96*16-48,in0
 	;;
-	stf.spill.nta [in0]=f54,32
-	stf.spill.nta [ r3]=f55,32
+	stf.spill.nta [loc2]=f46,-256
+	stf.spill.nta [loc3]=f38,-256
+	adds loc1=96*16-48-128,in0
 	;;
-	stf.spill.nta [in0]=f56,32
-	stf.spill.nta [ r3]=f57,32
+	stf.spill.nta [loc0]=f125,-256
+	stf.spill.nta [loc1]=f117,-256
 	;;
-	stf.spill.nta [in0]=f58,32
-	stf.spill.nta [ r3]=f59,32
+	stf.spill.nta [loc0]=f109,-256
+	stf.spill.nta [loc1]=f101,-256
 	;;
-	stf.spill.nta [in0]=f60,32
-	stf.spill.nta [ r3]=f61,32
+	stf.spill.nta [loc0]=f93,-256
+	stf.spill.nta [loc1]=f85,-256
 	;;
-	stf.spill.nta [in0]=f62,32
-	stf.spill.nta [ r3]=f63,32
+	stf.spill.nta [loc0]=f77,-256
+	stf.spill.nta [loc1]=f69,-256
 	;;
-	stf.spill.nta [in0]=f64,32
-	stf.spill.nta [ r3]=f65,32
+	stf.spill.nta [loc0]=f61,-256
+	stf.spill.nta [loc1]=f53,-256
+	adds loc2=96*16-64,in0
 	;;
-	stf.spill.nta [in0]=f66,32
-	stf.spill.nta [ r3]=f67,32
+	stf.spill.nta [loc0]=f45,-256
+	stf.spill.nta [loc1]=f37,-256
+	adds loc3=96*16-64-128,in0
 	;;
-	stf.spill.nta [in0]=f68,32
-	stf.spill.nta [ r3]=f69,32
+	stf.spill.nta [loc2]=f124,-256
+	stf.spill.nta [loc3]=f116,-256
 	;;
-	stf.spill.nta [in0]=f70,32
-	stf.spill.nta [ r3]=f71,32
+	stf.spill.nta [loc2]=f108,-256
+	stf.spill.nta [loc3]=f100,-256
 	;;
-	stf.spill.nta [in0]=f72,32
-	stf.spill.nta [ r3]=f73,32
+	stf.spill.nta [loc2]=f92,-256
+	stf.spill.nta [loc3]=f84,-256
 	;;
-	stf.spill.nta [in0]=f74,32
-	stf.spill.nta [ r3]=f75,32
+	stf.spill.nta [loc2]=f76,-256
+	stf.spill.nta [loc3]=f68,-256
 	;;
-	stf.spill.nta [in0]=f76,32
-	stf.spill.nta [ r3]=f77,32
+	stf.spill.nta [loc2]=f60,-256
+	stf.spill.nta [loc3]=f52,-256
+	adds loc0=96*16-80,in0
 	;;
-	stf.spill.nta [in0]=f78,32
-	stf.spill.nta [ r3]=f79,32
+	stf.spill.nta [loc2]=f44,-256
+	stf.spill.nta [loc3]=f36,-256
+	adds loc1=96*16-80-128,in0
 	;;
-	stf.spill.nta [in0]=f80,32
-	stf.spill.nta [ r3]=f81,32
+	stf.spill.nta [loc0]=f123,-256
+	stf.spill.nta [loc1]=f115,-256
 	;;
-	stf.spill.nta [in0]=f82,32
-	stf.spill.nta [ r3]=f83,32
+	stf.spill.nta [loc0]=f107,-256
+	stf.spill.nta [loc1]=f99,-256
 	;;
-	stf.spill.nta [in0]=f84,32
-	stf.spill.nta [ r3]=f85,32
+	stf.spill.nta [loc0]=f91,-256
+	stf.spill.nta [loc1]=f83,-256
 	;;
-	stf.spill.nta [in0]=f86,32
-	stf.spill.nta [ r3]=f87,32
+	stf.spill.nta [loc0]=f75,-256
+	stf.spill.nta [loc1]=f67,-256
 	;;
-	stf.spill.nta [in0]=f88,32
-	stf.spill.nta [ r3]=f89,32
+	stf.spill.nta [loc0]=f59,-256
+	stf.spill.nta [loc1]=f51,-256
+	adds loc2=96*16-96,in0
 	;;
-	stf.spill.nta [in0]=f90,32
-	stf.spill.nta [ r3]=f91,32
+	stf.spill.nta [loc0]=f43,-256
+	stf.spill.nta [loc1]=f35,-256
+	adds loc3=96*16-96-128,in0
 	;;
-	stf.spill.nta [in0]=f92,32
-	stf.spill.nta [ r3]=f93,32
+	stf.spill.nta [loc2]=f122,-256
+	stf.spill.nta [loc3]=f114,-256
 	;;
-	stf.spill.nta [in0]=f94,32
-	stf.spill.nta [ r3]=f95,32
+	stf.spill.nta [loc2]=f106,-256
+	stf.spill.nta [loc3]=f98,-256
 	;;
-	stf.spill.nta [in0]=f96,32
-	stf.spill.nta [ r3]=f97,32
+	stf.spill.nta [loc2]=f90,-256
+	stf.spill.nta [loc3]=f82,-256
 	;;
-	stf.spill.nta [in0]=f98,32
-	stf.spill.nta [ r3]=f99,32
+	stf.spill.nta [loc2]=f74,-256
+	stf.spill.nta [loc3]=f66,-256
 	;;
-	stf.spill.nta [in0]=f100,32
-	stf.spill.nta [ r3]=f101,32
+	stf.spill.nta [loc2]=f58,-256
+	stf.spill.nta [loc3]=f50,-256
+	adds loc0=96*16-112,in0
 	;;
-	stf.spill.nta [in0]=f102,32
-	stf.spill.nta [ r3]=f103,32
+	stf.spill.nta [loc2]=f42,-256
+	stf.spill.nta [loc3]=f34,-256
+	adds loc1=96*16-112-128,in0
 	;;
-	stf.spill.nta [in0]=f104,32
-	stf.spill.nta [ r3]=f105,32
+	stf.spill.nta [loc0]=f121,-256
+	stf.spill.nta [loc1]=f113,-256
 	;;
-	stf.spill.nta [in0]=f106,32
-	stf.spill.nta [ r3]=f107,32
+	stf.spill.nta [loc0]=f105,-256
+	stf.spill.nta [loc1]=f97,-256
 	;;
-	stf.spill.nta [in0]=f108,32
-	stf.spill.nta [ r3]=f109,32
+	stf.spill.nta [loc0]=f89,-256
+	stf.spill.nta [loc1]=f81,-256
 	;;
-	stf.spill.nta [in0]=f110,32
-	stf.spill.nta [ r3]=f111,32
+	stf.spill.nta [loc0]=f73,-256
+	stf.spill.nta [loc1]=f65,-256
 	;;
-	stf.spill.nta [in0]=f112,32
-	stf.spill.nta [ r3]=f113,32
+	stf.spill.nta [loc0]=f57,-256
+	stf.spill.nta [loc1]=f49,-256
+	adds loc2=96*16-128,in0
 	;;
-	stf.spill.nta [in0]=f114,32
-	stf.spill.nta [ r3]=f115,32
+	stf.spill.nta [loc0]=f41,-256
+	stf.spill.nta [loc1]=f33,-256
+	adds loc3=96*16-128-128,in0
 	;;
-	stf.spill.nta [in0]=f116,32
-	stf.spill.nta [ r3]=f117,32
+	stf.spill.nta [loc2]=f120,-256
+	stf.spill.nta [loc3]=f112,-256
 	;;
-	stf.spill.nta [in0]=f118,32
-	stf.spill.nta [ r3]=f119,32
+	stf.spill.nta [loc2]=f104,-256
+	stf.spill.nta [loc3]=f96,-256
 	;;
-	stf.spill.nta [in0]=f120,32
-	stf.spill.nta [ r3]=f121,32
+	stf.spill.nta [loc2]=f88,-256
+	stf.spill.nta [loc3]=f80,-256
 	;;
-	stf.spill.nta [in0]=f122,32
-	stf.spill.nta [ r3]=f123,32
+	stf.spill.nta [loc2]=f72,-256
+	stf.spill.nta [loc3]=f64,-256
 	;;
-	stf.spill.nta [in0]=f124,32
-	stf.spill.nta [ r3]=f125,32
+	stf.spill.nta [loc2]=f56,-256
+	stf.spill.nta [loc3]=f48,-256
 	;;
-	stf.spill.nta [in0]=f126,32
-	stf.spill.nta [ r3]=f127,32
+	stf.spill.nta [loc2]=f40
+	stf.spill.nta [loc3]=f32
 	br.ret.sptk.many rp
 END(__ia64_save_fpu)
 
 GLOBAL_ENTRY(__ia64_load_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
-	;;
-	ldf.fill.nta f32=[in0],32
-	ldf.fill.nta f33=[ r3],32
-	;;
-	ldf.fill.nta f34=[in0],32
-	ldf.fill.nta f35=[ r3],32
-	;;
-	ldf.fill.nta f36=[in0],32
-	ldf.fill.nta f37=[ r3],32
-	;;
-	ldf.fill.nta f38=[in0],32
-	ldf.fill.nta f39=[ r3],32
-	;;
-	ldf.fill.nta f40=[in0],32
-	ldf.fill.nta f41=[ r3],32
-	;;
-	ldf.fill.nta f42=[in0],32
-	ldf.fill.nta f43=[ r3],32
-	;;
-	ldf.fill.nta f44=[in0],32
-	ldf.fill.nta f45=[ r3],32
-	;;
-	ldf.fill.nta f46=[in0],32
-	ldf.fill.nta f47=[ r3],32
-	;;
-	ldf.fill.nta f48=[in0],32
-	ldf.fill.nta f49=[ r3],32
-	;;
-	ldf.fill.nta f50=[in0],32
-	ldf.fill.nta f51=[ r3],32
-	;;
-	ldf.fill.nta f52=[in0],32
-	ldf.fill.nta f53=[ r3],32
-	;;
-	ldf.fill.nta f54=[in0],32
-	ldf.fill.nta f55=[ r3],32
-	;;
-	ldf.fill.nta f56=[in0],32
-	ldf.fill.nta f57=[ r3],32
-	;;
-	ldf.fill.nta f58=[in0],32
-	ldf.fill.nta f59=[ r3],32
-	;;
-	ldf.fill.nta f60=[in0],32
-	ldf.fill.nta f61=[ r3],32
-	;;
-	ldf.fill.nta f62=[in0],32
-	ldf.fill.nta f63=[ r3],32
-	;;
-	ldf.fill.nta f64=[in0],32
-	ldf.fill.nta f65=[ r3],32
-	;;
-	ldf.fill.nta f66=[in0],32
-	ldf.fill.nta f67=[ r3],32
-	;;
-	ldf.fill.nta f68=[in0],32
-	ldf.fill.nta f69=[ r3],32
-	;;
-	ldf.fill.nta f70=[in0],32
-	ldf.fill.nta f71=[ r3],32
-	;;
-	ldf.fill.nta f72=[in0],32
-	ldf.fill.nta f73=[ r3],32
-	;;
-	ldf.fill.nta f74=[in0],32
-	ldf.fill.nta f75=[ r3],32
-	;;
-	ldf.fill.nta f76=[in0],32
-	ldf.fill.nta f77=[ r3],32
-	;;
-	ldf.fill.nta f78=[in0],32
-	ldf.fill.nta f79=[ r3],32
-	;;
-	ldf.fill.nta f80=[in0],32
-	ldf.fill.nta f81=[ r3],32
-	;;
-	ldf.fill.nta f82=[in0],32
-	ldf.fill.nta f83=[ r3],32
-	;;
-	ldf.fill.nta f84=[in0],32
-	ldf.fill.nta f85=[ r3],32
-	;;
-	ldf.fill.nta f86=[in0],32
-	ldf.fill.nta f87=[ r3],32
-	;;
-	ldf.fill.nta f88=[in0],32
-	ldf.fill.nta f89=[ r3],32
-	;;
-	ldf.fill.nta f90=[in0],32
-	ldf.fill.nta f91=[ r3],32
-	;;
-	ldf.fill.nta f92=[in0],32
-	ldf.fill.nta f93=[ r3],32
-	;;
-	ldf.fill.nta f94=[in0],32
-	ldf.fill.nta f95=[ r3],32
-	;;
-	ldf.fill.nta f96=[in0],32
-	ldf.fill.nta f97=[ r3],32
-	;;
-	ldf.fill.nta f98=[in0],32
-	ldf.fill.nta f99=[ r3],32
-	;;
-	ldf.fill.nta f100=[in0],32
-	ldf.fill.nta f101=[ r3],32
-	;;
-	ldf.fill.nta f102=[in0],32
-	ldf.fill.nta f103=[ r3],32
-	;;
-	ldf.fill.nta f104=[in0],32
-	ldf.fill.nta f105=[ r3],32
-	;;
-	ldf.fill.nta f106=[in0],32
-	ldf.fill.nta f107=[ r3],32
-	;;
-	ldf.fill.nta f108=[in0],32
-	ldf.fill.nta f109=[ r3],32
-	;;
-	ldf.fill.nta f110=[in0],32
-	ldf.fill.nta f111=[ r3],32
-	;;
-	ldf.fill.nta f112=[in0],32
-	ldf.fill.nta f113=[ r3],32
-	;;
-	ldf.fill.nta f114=[in0],32
-	ldf.fill.nta f115=[ r3],32
-	;;
-	ldf.fill.nta f116=[in0],32
-	ldf.fill.nta f117=[ r3],32
-	;;
-	ldf.fill.nta f118=[in0],32
-	ldf.fill.nta f119=[ r3],32
-	;;
-	ldf.fill.nta f120=[in0],32
-	ldf.fill.nta f121=[ r3],32
-	;;
-	ldf.fill.nta f122=[in0],32
-	ldf.fill.nta f123=[ r3],32
-	;;
-	ldf.fill.nta f124=[in0],32
-	ldf.fill.nta f125=[ r3],32
-	;;
-	ldf.fill.nta f126=[in0],32
-	ldf.fill.nta f127=[ r3],32
+	alloc r2=ar.pfs,1,2,0,0
+	adds r3=128,in0
+	adds r14=256,in0
+	adds r15=384,in0
+	mov loc0=512
+	mov loc1=-1024+16
+	;;
+	ldf.fill.nta f32=[in0],loc0
+	ldf.fill.nta f40=[ r3],loc0
+	ldf.fill.nta f48=[r14],loc0
+	ldf.fill.nta f56=[r15],loc0
+	;;
+	ldf.fill.nta f64=[in0],loc0
+	ldf.fill.nta f72=[ r3],loc0
+	ldf.fill.nta f80=[r14],loc0
+	ldf.fill.nta f88=[r15],loc0
+	;;
+	ldf.fill.nta f96=[in0],loc1
+	ldf.fill.nta f104=[ r3],loc1
+	ldf.fill.nta f112=[r14],loc1
+	ldf.fill.nta f120=[r15],loc1
+	;;
+	ldf.fill.nta f33=[in0],loc0
+	ldf.fill.nta f41=[ r3],loc0
+	ldf.fill.nta f49=[r14],loc0
+	ldf.fill.nta f57=[r15],loc0
+	;;
+	ldf.fill.nta f65=[in0],loc0
+	ldf.fill.nta f73=[ r3],loc0
+	ldf.fill.nta f81=[r14],loc0
+	ldf.fill.nta f89=[r15],loc0
+	;;
+	ldf.fill.nta f97=[in0],loc1
+	ldf.fill.nta f105=[ r3],loc1
+	ldf.fill.nta f113=[r14],loc1
+	ldf.fill.nta f121=[r15],loc1
+	;;
+	ldf.fill.nta f34=[in0],loc0
+	ldf.fill.nta f42=[ r3],loc0
+	ldf.fill.nta f50=[r14],loc0
+	ldf.fill.nta f58=[r15],loc0
+	;;
+	ldf.fill.nta f66=[in0],loc0
+	ldf.fill.nta f74=[ r3],loc0
+	ldf.fill.nta f82=[r14],loc0
+	ldf.fill.nta f90=[r15],loc0
+	;;
+	ldf.fill.nta f98=[in0],loc1
+	ldf.fill.nta f106=[ r3],loc1
+	ldf.fill.nta f114=[r14],loc1
+	ldf.fill.nta f122=[r15],loc1
+	;;
+	ldf.fill.nta f35=[in0],loc0
+	ldf.fill.nta f43=[ r3],loc0
+	ldf.fill.nta f51=[r14],loc0
+	ldf.fill.nta f59=[r15],loc0
+	;;
+	ldf.fill.nta f67=[in0],loc0
+	ldf.fill.nta f75=[ r3],loc0
+	ldf.fill.nta f83=[r14],loc0
+	ldf.fill.nta f91=[r15],loc0
+	;;
+	ldf.fill.nta f99=[in0],loc1
+	ldf.fill.nta f107=[ r3],loc1
+	ldf.fill.nta f115=[r14],loc1
+	ldf.fill.nta f123=[r15],loc1
+	;;
+	ldf.fill.nta f36=[in0],loc0
+	ldf.fill.nta f44=[ r3],loc0
+	ldf.fill.nta f52=[r14],loc0
+	ldf.fill.nta f60=[r15],loc0
+	;;
+	ldf.fill.nta f68=[in0],loc0
+	ldf.fill.nta f76=[ r3],loc0
+	ldf.fill.nta f84=[r14],loc0
+	ldf.fill.nta f92=[r15],loc0
+	;;
+	ldf.fill.nta f100=[in0],loc1
+	ldf.fill.nta f108=[ r3],loc1
+	ldf.fill.nta f116=[r14],loc1
+	ldf.fill.nta f124=[r15],loc1
+	;;
+	ldf.fill.nta f37=[in0],loc0
+	ldf.fill.nta f45=[ r3],loc0
+	ldf.fill.nta f53=[r14],loc0
+	ldf.fill.nta f61=[r15],loc0
+	;;
+	ldf.fill.nta f69=[in0],loc0
+	ldf.fill.nta f77=[ r3],loc0
+	ldf.fill.nta f85=[r14],loc0
+	ldf.fill.nta f93=[r15],loc0
+	;;
+	ldf.fill.nta f101=[in0],loc1
+	ldf.fill.nta f109=[ r3],loc1
+	ldf.fill.nta f117=[r14],loc1
+	ldf.fill.nta f125=[r15],loc1
+	;;
+	ldf.fill.nta f38 =[in0],loc0
+	ldf.fill.nta f46 =[ r3],loc0
+	ldf.fill.nta f54 =[r14],loc0
+	ldf.fill.nta f62 =[r15],loc0
+	;;
+	ldf.fill.nta f70 =[in0],loc0
+	ldf.fill.nta f78 =[ r3],loc0
+	ldf.fill.nta f86 =[r14],loc0
+	ldf.fill.nta f94 =[r15],loc0
+	;;
+	ldf.fill.nta f102=[in0],loc1
+	ldf.fill.nta f110=[ r3],loc1
+	ldf.fill.nta f118=[r14],loc1
+	ldf.fill.nta f126=[r15],loc1
+	;;
+	ldf.fill.nta f39 =[in0],loc0
+	ldf.fill.nta f47 =[ r3],loc0
+	ldf.fill.nta f55 =[r14],loc0
+	ldf.fill.nta f63 =[r15],loc0
+	;;
+	ldf.fill.nta f71 =[in0],loc0
+	ldf.fill.nta f79 =[ r3],loc0
+	ldf.fill.nta f87 =[r14],loc0
+	ldf.fill.nta f95 =[r15],loc0
+	;;
+	ldf.fill.nta f103=[in0]
+	ldf.fill.nta f111=[ r3]
+	ldf.fill.nta f119=[r14]
+	ldf.fill.nta f127=[r15]
 	br.ret.sptk.many rp
 END(__ia64_load_fpu)
 
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/ia64_ksyms.c linux-2.4.21-pre2/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.21-pre1/arch/ia64/kernel/ia64_ksyms.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/ia64_ksyms.c	Wed Dec 18 14:16:26 2002
@@ -57,6 +57,10 @@
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
+#include <asm/pgtable.h>
+EXPORT_SYMBOL(vmalloc_end);
+EXPORT_SYMBOL(ia64_page_valid);
+
 #include <asm/processor.h>
 # ifndef CONFIG_NUMA
 EXPORT_SYMBOL(_cpu_data);
@@ -100,7 +104,7 @@
 
 #else /* !CONFIG_SMP */
 
-EXPORT_SYMBOL(__flush_tlb_all);
+EXPORT_SYMBOL(local_flush_tlb_all);
 
 #endif /* !CONFIG_SMP */
 
@@ -141,6 +145,8 @@
 EXPORT_SYMBOL(ia64_pal_call_phys_static);
 EXPORT_SYMBOL(ia64_pal_call_stacked);
 EXPORT_SYMBOL(ia64_pal_call_static);
+EXPORT_SYMBOL(ia64_load_scratch_fpregs);
+EXPORT_SYMBOL(ia64_save_scratch_fpregs);
 
 extern struct efi efi;
 EXPORT_SYMBOL(efi);
@@ -154,4 +160,8 @@
 EXPORT_SYMBOL(ia64_mv);
 #endif
 EXPORT_SYMBOL(machvec_noop);
-
+#ifdef CONFIG_PERFMON
+#include <asm/perfmon.h>
+EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem);
+EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem);
+#endif
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/iosapic.c linux-2.4.21-pre2/arch/ia64/kernel/iosapic.c
--- linux-2.4.21-pre1/arch/ia64/kernel/iosapic.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/iosapic.c	Wed Dec 18 14:16:26 2002
@@ -590,7 +590,7 @@
 		      gsi_base, addr);
 
 	DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, global_vector,
+	    isa_irq, gsi,
 	    polarity ? "high" : "low", edge_triggered ? "edge" : "level",
 	    dest, vector);
 
@@ -661,7 +661,7 @@
 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
 			      0, 0, gsi_base, addr);
 
-		DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
+		DBG("PCI: (%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
 		    segment, bus, slot, 'A' + pci_pin, gsi, vector);
 	}
 
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/irq.c linux-2.4.21-pre2/arch/ia64/kernel/irq.c
--- linux-2.4.21-pre1/arch/ia64/kernel/irq.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/irq.c	Wed Dec 18 14:16:26 2002
@@ -1060,7 +1060,7 @@
 
 	if (!shared) {
 		desc->depth = 0;
-		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
 		desc->handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/irq_ia64.c linux-2.4.21-pre2/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.21-pre1/arch/ia64/kernel/irq_ia64.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/irq_ia64.c	Wed Dec 18 14:16:26 2002
@@ -178,7 +178,7 @@
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 	platform_irq_init();
 }
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/machvec.c linux-2.4.21-pre2/arch/ia64/kernel/machvec.c
--- linux-2.4.21-pre1/arch/ia64/kernel/machvec.c	Thu Jan  4 12:50:17 2001
+++ linux-2.4.21-pre2/arch/ia64/kernel/machvec.c	Wed Dec 18 14:16:26 2002
@@ -15,7 +15,7 @@
  * into a memory map index.
  */
 unsigned long
-map_nr_dense (unsigned long addr)
+map_nr_dense (void *addr)
 {
 	return MAP_NR_DENSE(addr);
 }
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/mca.c linux-2.4.21-pre2/arch/ia64/kernel/mca.c
--- linux-2.4.21-pre1/arch/ia64/kernel/mca.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/mca.c	Wed Dec 18 14:16:26 2002
@@ -42,6 +42,9 @@
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -69,10 +72,10 @@
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 u64				ia64_mca_sal_data_area[1356];
-u64				ia64_mca_min_state_save_info;
 u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
-
+/* TODO: need to assign min-state structure to UC memory */
+u64				ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -105,6 +108,11 @@
 	name:       "cpe_hndlr"
 };
 
+#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
+#define MIN_CPE_POLL_INTERVAL (2*60*HZ)  /* 2 minutes */
+
+static struct timer_list cpe_poll_timer;
+
 /*
  *  ia64_mca_log_sal_error_record
  *
@@ -116,7 +124,7 @@
  *  Outputs :   platform error status
  */
 int
-ia64_mca_log_sal_error_record(int sal_info_type)
+ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
 {
 	int platform_err = 0;
 
@@ -131,7 +139,10 @@
 	 */
 
 	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
-	ia64_sal_clear_state_info(sal_info_type);
+	/* temporary: only clear SAL logs on hardware-corrected errors
+		or if we're logging an error after an MCA-initiated reboot */
+	if ((sal_info_type > 1) || (called_from_init))
+		ia64_sal_clear_state_info(sal_info_type);
 
 	return platform_err;
 }
@@ -152,7 +163,7 @@
 	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
 }
 
 /*
@@ -205,7 +216,7 @@
 	/*
 	 *  If there is an MCA error record pending, get it and log it.
 	 */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
 }
 
 /*
@@ -257,15 +268,23 @@
  *
  */
 void
-ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
+ia64_process_min_state_save (pal_min_state_area_t *pmss)
 {
-	int i, max=57;
-	u64 *tpmss_ptr=(u64 *)pmss;
+	int i, max = MIN_STATE_AREA_SIZE;
+	u64 *tpmss_ptr = (u64 *)pmss;
+	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
 
 	/* dump out the min_state_area information */
 
 	for (i=0;i<max;i++) {
 
+		/* copy min-state register info for eventual return to PAL */
+		*return_min_state_ptr++ = *tpmss_ptr;
+
+#if 1
+		tpmss_ptr++;  /* skip to next entry */
+#else
+		/* the printing part */
 		if(!ia64_pmss_dump_bank0) {
 			if(strncmp("B0",min_state_labels[i],2)==0) {
 				tpmss_ptr++;  /* skip to next entry */
@@ -278,6 +297,7 @@
 		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
 				     && !ia64_pmss_dump_bank0))
 			printk("\n");
+#endif
 	}
 }
 
@@ -510,8 +530,7 @@
 					setup_irq(irq, &mca_cpe_irqaction);
 				}
 			ia64_mca_register_cpev(cpev);
-		} else
-			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+		}
 	}
 
 	/* Initialize the areas set aside by the OS to buffer the
@@ -523,19 +542,17 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC);
 	ia64_log_init(SAL_INFO_TYPE_CPE);
 
-	/* Zero the min state save info */
-	ia64_mca_min_state_save_info = 0;
-
 #if defined(MCA_TEST)
 	mca_test();
 #endif /* #if defined(MCA_TEST) */
 
 	printk("Mca related initialization done\n");
 
-#if 0   // Too early in initialization -- error log is lost
+	/* commented out because this is done elsewhere */
+#if 0
 	/* Do post-failure MCA error logging */
 	ia64_mca_check_errors();
-#endif  // Too early in initialization -- error log is lost
+#endif
 }
 
 /*
@@ -701,8 +718,8 @@
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
 
 	/* Register pointer to new min state values */
-	/* NOTE: need to do something with this during recovery phase */
-	ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info;
+	ia64_os_to_sal_handoff_state.imots_new_min_state =
+		(pal_min_state_area_t *)ia64_mca_min_state_save_info;
 }
 
 /*
@@ -727,7 +744,7 @@
 	int platform_err = 0;
 
 	/* Get the MCA error record and log it */
-	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
 
 	/*
 	 *  Do Platform-specific mca error handling if required.
@@ -767,7 +784,7 @@
 		       cmc_irq, smp_processor_id());
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
 }
 
 /*
@@ -803,6 +820,62 @@
 #define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
 
 /*
+ *  ia64_mca_cpe_poll
+ *
+ *	Poll for Corrected Platform Errors (CPEs), dynamically adjust
+ *	polling interval based on occurance of an event.
+ *
+ * Inputs   :   dummy(unused)
+ * Outputs  :   None
+ *
+ */
+static void
+ia64_mca_cpe_poll (unsigned long dummy)
+{
+	int start_index;
+	static int poll_time = MAX_CPE_POLL_INTERVAL;
+
+	start_index = IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE);
+
+	/* Call the interrupt handler */
+	ia64_mca_cpe_int_handler(0, NULL, NULL);
+
+	/*
+	 * If a log was recorded, increase our polling frequency,
+	 * otherwise, backoff.
+	 */
+	if (start_index != IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE)) {
+		poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time/2);
+	} else {
+		poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2);
+	}
+	mod_timer(&cpe_poll_timer, jiffies + poll_time);
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ *	Opportunity to setup things that require initialization later
+ *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *	platform doesn't support an interrupt driven mechanism.
+ *
+ *  Inputs  :   None
+ *  Outputs :   Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0) {
+		init_timer(&cpe_poll_timer);
+		cpe_poll_timer.function = ia64_mca_cpe_poll;
+		ia64_mca_cpe_poll(0);
+	}
+	return 0;
+}
+
+module_init(ia64_mca_late_init);
+
+/*
  * C portion of the OS INIT handler
  *
  * Called from ia64_monarch_init_handler
@@ -837,8 +910,7 @@
 	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
 	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
-				    regs);
+	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area);
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
@@ -962,7 +1034,6 @@
 		return total_len;
 	} else {
 		IA64_LOG_UNLOCK(sal_info_type);
-		prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
 		return 0;
 	}
 }
@@ -1004,28 +1075,13 @@
 void
 ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
 {
-	char str_buf[32];
-
-	sprintf(str_buf, "%2d.%02d",
-		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
-		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
-	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
-	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
-		(lh->timestamp.slh_month >> 4) * 10 +
-		(lh->timestamp.slh_month & 0xf),
-		(lh->timestamp.slh_day >> 4) * 10 +
-		(lh->timestamp.slh_day & 0xf),
-		(lh->timestamp.slh_century >> 4) * 1000 +
-		(lh->timestamp.slh_century & 0xf) * 100 +
-		(lh->timestamp.slh_year >> 4) * 10 +
-		(lh->timestamp.slh_year & 0xf),
-		(lh->timestamp.slh_hour >> 4) * 10 +
-		(lh->timestamp.slh_hour & 0xf),
-		(lh->timestamp.slh_minute >> 4) * 10 +
-		(lh->timestamp.slh_minute & 0xf),
-		(lh->timestamp.slh_second >> 4) * 10 +
-		(lh->timestamp.slh_second & 0xf));
-	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
+	prfunc("+Err Record ID: %d    SAL Rev: %2x.%02x\n", lh->id,
+		lh->revision.major, lh->revision.minor);
+	prfunc("+Time: %02x/%02x/%02x%02x %02d:%02d:%02d    Severity %d\n",
+		lh->timestamp.slh_month, lh->timestamp.slh_day,
+		lh->timestamp.slh_century, lh->timestamp.slh_year,
+		lh->timestamp.slh_hour, lh->timestamp.slh_minute,
+		lh->timestamp.slh_second, lh->severity);
 }
 
 /*
@@ -1684,6 +1740,9 @@
 	if (slpi->valid.psi_static_struct) {
 		spsi = (sal_processor_static_info_t *)p_data;
 
+		/* copy interrupted context PAL min-state info */
+		ia64_process_min_state_save(&spsi->min_state_area);
+
 		/* Print branch register contents if valid */
 		if (spsi->valid.br)
 			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/pal.S linux-2.4.21-pre2/arch/ia64/kernel/pal.S
--- linux-2.4.21-pre1/arch/ia64/kernel/pal.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/pal.S	Wed Dec 18 14:16:26 2002
@@ -245,3 +245,49 @@
 	br.ret.sptk.many b0
 END(ia64_pal_call_phys_stacked)
 
+/*
+ * Save scratch fp scratch regs (fp10-fp15)
+ *
+ * NOTE: We need to do this since firmware (SAL or PAL) uses more
+ * scratch fp regs than the Linux kernel does.
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_save_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	stf.spill [in0] = f10,32
+	stf.spill [r2]  = f11,32
+	;;
+	stf.spill [in0] = f12,32
+	stf.spill [r2]  = f13,32
+	;;
+	stf.spill [in0] = f14,32
+	stf.spill [r2]  = f15,32
+	br.ret.sptk.many rp
+END(ia64_save_scratch_fpregs)
+
+/*
+ * Load scratch fp scratch regs (fp10-fp15)
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_load_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	ldf.fill  f10 = [in0],32
+	ldf.fill  f11 = [r2],32
+	;;
+	ldf.fill  f12 = [in0],32
+	ldf.fill  f13 = [r2],32
+	;;
+	ldf.fill  f14 = [in0],32
+	ldf.fill  f15 = [r2],32
+	br.ret.sptk.many rp
+END(ia64_load_scratch_fpregs)
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/pci.c linux-2.4.21-pre2/arch/ia64/kernel/pci.c
--- linux-2.4.21-pre1/arch/ia64/kernel/pci.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/pci.c	Wed Dec 18 14:16:26 2002
@@ -43,6 +43,8 @@
 extern void ia64_mca_check_errors( void );
 #endif
 
+static unsigned int acpi_root_bridges;
+
 struct pci_fixup pcibios_fixups[1];
 
 struct pci_ops *pci_root_ops;
@@ -217,7 +219,7 @@
 	struct pci_controller *controller;
 	u64 base, size, offset;
 
-	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+	acpi_root_bridges++;
 
 	controller = alloc_pci_controller(seg);
 	if (!controller)
@@ -249,7 +251,7 @@
 void __init
 pcibios_init (void)
 {
-#	define PCI_BUSES_TO_SCAN 255
+#	define PCI_BUSES_TO_SCAN 256
 	int i = 0;
 	struct pci_controller *controller;
 
@@ -261,11 +263,14 @@
 
 	platform_pci_fixup(0);	/* phase 0 fixups (before buses scanned) */
 
-	printk("PCI: Probing PCI hardware\n");
-	controller = alloc_pci_controller(0);
-	if (controller)
-		for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-			pci_scan_bus(i, pci_root_ops, controller);
+	/* Only probe blindly if ACPI didn't tell us about root bridges */
+	if (!acpi_root_bridges) {
+		printk("PCI: Probing PCI hardware\n");
+		controller = alloc_pci_controller(0);
+		if (controller)
+			for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+				pci_scan_bus(i, pci_root_ops, controller);
+	}
 
 	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
 
@@ -294,10 +299,9 @@
 }
 
 /*
- *  Called after each bus is probed, but before its children
- *  are examined.
+ *  Called after each bus is probed, but before its children are examined.
  */
-void __init
+void __devinit
 pcibios_fixup_bus (struct pci_bus *b)
 {
 	struct list_head *ln;
@@ -306,7 +310,7 @@
 		pcibios_fixup_device_resources(pci_dev_b(ln), b);
 }
 
-void __init
+void __devinit
 pcibios_update_resource (struct pci_dev *dev, struct resource *root,
 			 struct resource *res, int resource)
 {
@@ -322,7 +326,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_update_irq (struct pci_dev *dev, int irq)
 {
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -330,7 +334,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
 	ranges->io_start -= bus->resource[0]->start;
@@ -339,8 +343,8 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-int
-pcibios_enable_device (struct pci_dev *dev)
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -349,11 +353,13 @@
 	if (!dev)
 		return -EINVAL;
 
- 	platform_pci_enable_device(dev);
-
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		/* Only set up the desired resources.  */
+		if (!(mask & (1 << idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR
@@ -372,6 +378,19 @@
 		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
+	return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+	int ret;
+
+	ret = pcibios_enable_resources(dev, mask);
+	if (ret < 0)
+		return ret;
+
+ 	platform_pci_enable_device(dev);
 
 	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
 
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/perfmon.c linux-2.4.21-pre2/arch/ia64/kernel/perfmon.c
--- linux-2.4.21-pre1/arch/ia64/kernel/perfmon.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/perfmon.c	Wed Dec 18 14:16:26 2002
@@ -28,7 +28,6 @@
 #include <asm/bitops.h>
 #include <asm/errno.h>
 #include <asm/page.h>
-#include <asm/pal.h>
 #include <asm/perfmon.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
@@ -56,27 +55,53 @@
 /*
  * Reset register flags
  */
-#define PFM_RELOAD_LONG_RESET	1
-#define PFM_RELOAD_SHORT_RESET	2
+#define PFM_PMD_LONG_RESET	1
+#define PFM_PMD_SHORT_RESET	2
 
 /*
  * Misc macros and definitions
  */
 #define PMU_FIRST_COUNTER	4
+#define PMU_MAX_PMCS		256
+#define PMU_MAX_PMDS		256
 
-#define PFM_IS_DISABLED() pmu_conf.pfm_is_disabled
+/*
+ * type of a PMU register (bitmask).
+ * bitmask structure:
+ * 	bit0   : register implemented
+ * 	bit1   : end marker 
+ * 	bit2-3 : reserved
+ * 	bit4-7 : register type
+ * 	bit8-31: reserved
+ */
+#define PFM_REG_IMPL		0x1 /* register implemented */
+#define PFM_REG_END		0x2 /* end marker */
+#define PFM_REG_MONITOR		(0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */
+#define PFM_REG_COUNTING	(0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+#define PFM_REG_CONTROL		(0x3<<4|PFM_REG_IMPL) /* PMU control register */
+#define	PFM_REG_CONFIG		(0x4<<4|PFM_REG_IMPL) /* refine configuration */
+#define PFM_REG_BUFFER	 	(0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */
+
+#define PMC_IS_LAST(i)	(pmu_conf.pmc_desc[i].type & PFM_REG_END)
+#define PMD_IS_LAST(i)	(pmu_conf.pmd_desc[i].type & PFM_REG_END)
+
+#define PFM_IS_DISABLED() pmu_conf.disabled
 
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
 /* i assume unsigned */
-#define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
-#define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
+#define PMC_IS_IMPL(i)	  (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL))
+#define PMD_IS_IMPL(i)	  (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL))
 
 /* XXX: these three assume that register i is implemented */
 #define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
 #define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
-#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_IS_MONITOR(i)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_DFL_VAL(i)     pmu_conf.pmc_desc[i].default_value
+#define PMC_RSVD_MASK(i)   pmu_conf.pmc_desc[i].reserved_mask
+#define PMD_PMD_DEP(i)	   pmu_conf.pmd_desc[i].dep_pmd[0]
+#define PMC_PMD_DEP(i)	   pmu_conf.pmc_desc[i].dep_pmd[0]
 
 /* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
@@ -176,28 +201,17 @@
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
 /*
- * The possible type of a PMU register
- */
-typedef enum { 
-	PFM_REG_NOTIMPL, /* not implemented */
-	PFM_REG_NONE, 	 /* end marker */
-	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
-	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
-	PFM_REG_CONTROL, /* PMU control register */
-	PFM_REG_CONFIG,  /* refine configuration */
-	PFM_REG_BUFFER	 /* PMD used as buffer */
-} pfm_pmu_reg_type_t;
-
-/*
  * 64-bit software counter structure
  */
 typedef struct {
 	u64 val;	/* virtual 64bit counter value */
-	u64 ival;	/* initial value from user */
+	u64 lval;	/* last value */
 	u64 long_reset;	/* reset value on sampling overflow */
 	u64 short_reset;/* reset value on overflow */
 	u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */
-	int flags;	/* notify/do not notify */
+	u64 seed;	/* seed for random-number generator */
+	u64 mask;	/* mask for random-number generator */
+	unsigned int flags; /* notify/do not notify */
 } pfm_counter_t;
 
 /*
@@ -268,10 +282,10 @@
 typedef struct {
 	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	unsigned int 		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned int		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned int		pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned int		pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
 	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
@@ -281,13 +295,16 @@
  * dep_pmc[]: a bitmask of dependent PMC registers
  */
 typedef struct {
-	pfm_pmu_reg_type_t	type;
+	unsigned int		type;
 	int			pm_pos;
+	unsigned long		default_value;	/* power-on default value */
+	unsigned long		reserved_mask;	/* bitmask of reserved bits */
 	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	unsigned long		dep_pmd[4];
 	unsigned long		dep_pmc[4];
 } pfm_reg_desc_t;
+
 /* assume cnum is a valid monitor */
 #define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
 #define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
@@ -296,23 +313,22 @@
 
 /*
  * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL along with a list of inter-registers dependencies and configurations.
+ * a description of the PMU main characteristics.
  */
 typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
-	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+	unsigned int  disabled;		/* indicates if perfmon is working properly */
+	unsigned long ovfl_val;		/* overflow value for generic counters   */
+	unsigned long impl_pmcs[4];	/* bitmask of implemented PMCS */
+	unsigned long impl_pmds[4];	/* bitmask of implemented PMDS */
+	unsigned int  num_pmcs;		/* number of implemented PMCS */
+	unsigned int  num_pmds;		/* number of implemented PMDS */
+	unsigned int  num_ibrs;		/* number of implemented IBRS */
+	unsigned int  num_dbrs;		/* number of implemented DBRS */
+	unsigned int  num_counters;	/* number of PMD/PMC counters */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register dependencies descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register dependencies descriptions */
 } pmu_config_t;
 
-
 /*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
@@ -336,7 +352,7 @@
 
 #define PFM_CMD_PID		0x1	/* command requires pid argument */
 #define PFM_CMD_ARG_READ	0x2	/* command must read argument(s) */
-#define PFM_CMD_ARG_WRITE	0x4	/* command must write argument(s) */
+#define PFM_CMD_ARG_RW		0x4	/* command must read/write argument(s) */
 #define PFM_CMD_CTX		0x8	/* command needs a perfmon context */
 #define PFM_CMD_NOCHK		0x10	/* command does not need to check task's state */
 
@@ -347,7 +363,7 @@
 
 #define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)
 #define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)
-#define PFM_CMD_WRITE_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_WRITE) != 0)
+#define PFM_CMD_RW_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0)
 #define PFM_CMD_USE_CTX(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0)
 #define PFM_CMD_CHK(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0)
 
@@ -366,15 +382,16 @@
 	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
 	unsigned long pfm_recorded_samples_count;
 	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
 } pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
-static pmu_config_t	pmu_conf; 	/* PMU configuration */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static pfm_stats_t	pfm_stats;
+static pfm_stats_t	pfm_stats[NR_CPUS];
+static pfm_intr_handler_desc_t	*pfm_alternate_intr_handler;
 
 /* sysctl() controls */
 static pfm_sysctl_t pfm_sysctl;
@@ -395,8 +412,6 @@
 };
 static struct ctl_table_header *pfm_sysctl_header;
 
-static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
-
 static void pfm_vm_close(struct vm_area_struct * area);
 
 static struct vm_operations_struct pfm_vm_ops={
@@ -408,14 +423,15 @@
  */
 static struct {
 	struct task_struct *owner;
-} ____cacheline_aligned pmu_owners[NR_CPUS];
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
+} pmu_owners[NR_CPUS];
 
 
 
 /*
  * forward declarations
  */
-static void ia64_reset_pmu(struct task_struct *);
+static void pfm_reset_pmu(struct task_struct *);
 #ifdef CONFIG_SMP
 static void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx);
 #endif
@@ -432,40 +448,21 @@
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
-	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.perf_ovfl_val);
+	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val);
 }
 
 static inline void
 pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
 {
-	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.perf_ovfl_val;
+	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.ovfl_val;
 	/*
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
+	ia64_set_pmd(i, val & pmu_conf.ovfl_val);
 }
 
 /*
- * finds the number of PM(C|D) registers given
- * the bitvector returned by PAL
- */
-static unsigned long __init
-find_num_pm_regs(long *buffer)
-{
-	int i=3; /* 4 words/per bitvector */
-
-	/* start from the most significant word */
-	while (i>=0 && buffer[i] == 0 ) i--;
-	if (i< 0) {
-		printk(KERN_ERR "perfmon: No bit set in pm_buffer\n");
-		return 0;
-	}
-	return 1+ ia64_fls(buffer[i]) + 64 * i;
-}
-
-
-/*
  * Generates a unique (per CPU) timestamp
  */
 static inline unsigned long
@@ -767,15 +764,14 @@
 	psb = kmalloc(sizeof(*psb), GFP_KERNEL);
 	if (psb == NULL) {
 		DBprintk(("Can't allocate sampling buffer descriptor\n"));
-		pfm_rvfree(smpl_buf, size);
-		return -ENOMEM;
+		goto error_kmalloc;
 	}
 
 	/* allocate vma */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) {
 		DBprintk(("Cannot allocate vma\n"));
-		goto error;
+		goto error_kmem;
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
@@ -875,11 +871,126 @@
 	return 0;
 
 error:
-	pfm_rvfree(smpl_buf, size);
+	kmem_cache_free(vm_area_cachep, vma);
+error_kmem:
 	kfree(psb);
+error_kmalloc:
+	pfm_rvfree(smpl_buf, size);
 	return -ENOMEM;
 }
 
+static int
+pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	unsigned long m, undo_mask;
+	unsigned int n, i;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	if (is_syswide) {
+		/* 
+		 * cannot mix system wide and per-task sessions
+		 */
+		if (pfm_sessions.pfs_task_sessions > 0UL) {
+			DBprintk(("system wide not possible, %u conflicting task_sessions\n", 
+			  	pfm_sessions.pfs_task_sessions));
+			goto abort;
+		}
+
+		m = cpu_mask; undo_mask = 0UL; n = 0;
+		for(i=0; m; i++, m>>=1) {
+
+			if ((m & 0x1) == 0UL) continue;
+
+			if (pfm_sessions.pfs_sys_session[i]) goto undo;
+
+			DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id()));
+
+			pfm_sessions.pfs_sys_session[i] = task;
+			undo_mask |= 1UL << i;
+			n++;
+		}
+		pfm_sessions.pfs_sys_sessions += n;
+	} else {
+		if (pfm_sessions.pfs_sys_sessions) goto abort;
+		pfm_sessions.pfs_task_sessions++;
+	}
+	UNLOCK_PFS();
+	return 0;
+undo:
+	DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",
+  		pfm_sessions.pfs_sys_session[i]->pid, i));
+
+	for(i=0; undo_mask; i++, undo_mask >>=1) {
+		pfm_sessions.pfs_sys_session[i] = NULL;
+	}
+abort:
+	UNLOCK_PFS();
+
+	return -EBUSY;
+
+}
+
+static int
+pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	pfm_context_t *ctx;
+	unsigned long m;
+	unsigned int n, i;
+
+	ctx = task ? task->thread.pfm_context : NULL;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n",
+		task->pid,
+		pfm_sessions.pfs_sys_sessions,
+		pfm_sessions.pfs_task_sessions,
+		pfm_sessions.pfs_sys_use_dbregs,
+		is_syswide,
+		cpu_mask));
+		
+
+	if (is_syswide) {
+		m = cpu_mask; n = 0;
+		for(i=0; m; i++, m>>=1) {
+			if ((m & 0x1) == 0UL) continue;
+			pfm_sessions.pfs_sys_session[i] = NULL;
+			n++;
+		}
+		/* 
+		 * would not work with perfmon+more than one bit in cpu_mask
+		 */
+		if (ctx && ctx->ctx_fl_using_dbreg) {
+			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
+				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
+			} else {
+				pfm_sessions.pfs_sys_use_dbregs--;
+			}
+		}
+		pfm_sessions.pfs_sys_sessions -= n;
+
+		DBprintk(("CPU%d sys_sessions=%u\n", 
+			smp_processor_id(), pfm_sessions.pfs_sys_sessions));
+	} else {
+		pfm_sessions.pfs_task_sessions--;
+		DBprintk(("[%d] task_sessions=%u\n", 
+			task->pid, pfm_sessions.pfs_task_sessions));
+	}
+
+	UNLOCK_PFS();
+
+	return 0;
+}
+
+
+
 /*
  * XXX: do something better here
  */
@@ -895,6 +1006,7 @@
 static int
 pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx)
 {
+	unsigned long smpl_pmds = pfx->ctx_smpl_regs[0];
 	int ctx_flags;
 	int cpu;
 
@@ -961,6 +1073,11 @@
 		}
 #endif
 	}
+	/* verify validity of smpl_regs */
+	if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) {
+		DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds));
+		return -EINVAL;
+	}
 	/* probably more to add here */
 
 	return 0;
@@ -984,7 +1101,7 @@
 	 */
 	if (task != current) return -EINVAL;
 
-	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+	if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 	ret = pfx_is_sane(task, &tmp);
 	if (ret < 0) return ret;
@@ -993,38 +1110,8 @@
 
 	ret =  -EBUSY;
 
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-
-		/* at this point, we know there is at least one bit set */
-		cpu = ffz(~tmp.ctx_cpu_mask);
-
-		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
-
-		if (pfm_sessions.pfs_task_sessions > 0) {
-			DBprintk(("system wide not possible, task_sessions=%ld\n", pfm_sessions.pfs_task_sessions));
-			goto abort;
-		}
-
-		if (pfm_sessions.pfs_sys_session[cpu]) {
-			DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",pfm_sessions.pfs_sys_session[cpu]->pid, cpu));
-			goto abort;
-		}
-		pfm_sessions.pfs_sys_session[cpu] = task;
-		/*
-		 * count the number of system wide sessions
-		 */
-		pfm_sessions.pfs_sys_sessions++;
-
-	} else if (pfm_sessions.pfs_sys_sessions == 0) {
-		pfm_sessions.pfs_task_sessions++;
-	} else {
-		/* no per-process monitoring while there is a system wide session */
-		goto abort;
-	}
-
-	UNLOCK_PFS();
+	ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask);
+	if (ret) goto abort;
 
 	ret = -ENOMEM;
 
@@ -1040,8 +1127,8 @@
 
 	if (notify_pid == current->pid) {
 
-		ctx->ctx_notify_task = task = current;
-		current->thread.pfm_context = ctx;
+		ctx->ctx_notify_task = current;
+		task->thread.pfm_context = ctx;
 
 	} else if (notify_pid!=0) {
 		struct task_struct *notify_task;
@@ -1057,7 +1144,10 @@
 			/*
 			 * check if we can send this task a signal
 			 */
-			if (pfm_bad_permissions(notify_task)) goto buffer_error;
+			if (pfm_bad_permissions(notify_task)) {
+				read_unlock(&tasklist_lock);
+				goto buffer_error;
+			}
 
 			/* 
 		 	 * make visible
@@ -1067,7 +1157,7 @@
 		 	 * okay because child will do the scan for nothing which
 		 	 * won't hurt.
 		 	 */
-			current->thread.pfm_context = ctx;
+			task->thread.pfm_context = ctx;
 
 			/*
 			 * will cause task to check on exit for monitored
@@ -1124,7 +1214,7 @@
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-	if (copy_to_user(req, &tmp, sizeof(tmp))) {
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
 	}
@@ -1157,32 +1247,40 @@
 buffer_error:
 	pfm_context_free(ctx);
 error:
-	/*
-	 * undo session reservation
-	 */
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-		pfm_sessions.pfs_sys_session[cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
+	pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask);
 abort:
-	UNLOCK_PFS();
+	/* make sure we don't leave anything behind */
+	task->thread.pfm_context = NULL;
 
 	return ret;
 }
 
+static inline unsigned long
+pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
+{
+	unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;
+	unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;
+	extern unsigned long carta_random32 (unsigned long seed);
+
+	if (reg->flags & PFM_REGFL_RANDOM) {
+		new_seed = carta_random32(old_seed);
+		val -= (old_seed & mask);	/* counter values are negative numbers! */
+		if ((mask >> 32) != 0)
+			/* construct a full 64-bit random value: */
+			new_seed |= carta_random32(old_seed >> 32) << 32;
+		reg->seed = new_seed;
+	}
+	reg->lval = val;
+	return val;
+}
+
 static void
 pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
 {
 	unsigned long mask = ovfl_regs[0];
 	unsigned long reset_others = 0UL;
 	unsigned long val;
-	int i;
-
-	DBprintk(("masks=0x%lx\n", mask));
+	int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
 
 	/*
 	 * now restore reset value on sampling overflowed counters
@@ -1190,15 +1288,11 @@
 	mask >>= PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
 		if (mask & 0x1) {
-			val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
-
+			val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 			reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0];
 
-			DBprintk(("[%d] %s reset soft_pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+			DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid,
+				  is_long_reset ? "long" : "short", i, val));
 
 			/* upper part is ignored on rval */
 			pfm_write_soft_counter(ctx, i, val);
@@ -1212,23 +1306,17 @@
 
 		if ((reset_others & 0x1) == 0) continue;
 
-		val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
+		val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 
 		if (PMD_IS_COUNTING(i)) {
 			pfm_write_soft_counter(ctx, i, val);
 		} else {
 			ia64_set_pmd(i, val);
 		}
-
-		DBprintk(("[%d] %s reset_others pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+		DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid,
+			  is_long_reset ? "long" : "short", i, val));
 	}
 	ia64_srlz_d();
-	/* just in case ! */
-	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
@@ -1236,12 +1324,10 @@
 {
 	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long value, reset_pmds;
+	unsigned int cnum, reg_flags, flags;
 	int i;
-	int ret = 0, reg_retval = 0;
-
-	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	int ret = -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1249,10 +1335,13 @@
 
 	for (i = 0; i < count; i++, req++) {
 
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
-
-		cnum = tmp.reg_num;
+		cnum       = tmp.reg_num;
+		reg_flags  = tmp.reg_flags;
+		value      = tmp.reg_value;
+		reset_pmds = tmp.reg_reset_pmds[0];
+		flags      = 0;
 
 		/* 
 		 * we reject all non implemented PMC as well
@@ -1261,8 +1350,7 @@
 		 */
 		if (!PMC_IS_IMPL(cnum) || cnum < 4) {
 			DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum));
-			ret = -EINVAL;
-			goto abort_mission;
+			goto error;
 		}
 		/*
 		 * A PMC used to configure monitors must be:
@@ -1271,73 +1359,83 @@
 		 * any other configuration is rejected.
 		 */
 		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
-			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); 
 
-			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
-				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
-				ret = -EINVAL;
-				goto abort_mission;
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system));
+				goto error;
 			}
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			pfm_monitor_t *p = (pfm_monitor_t *)&value;
 			/*
 		 	 * enforce generation of overflow interrupt. Necessary on all
 		 	 * CPUs.
 		 	 */
 			p->pmc_oi = 1;
 
-			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
+			if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
-				 * must have a target for the signal
-				 */
+			 	 * must have a target for the signal
+			 	 */
 				if (ctx->ctx_notify_task == NULL) {
-					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
-					ret = -EINVAL;
-					goto abort_mission;
+					DBprintk(("cannot set ovfl_notify: no notify_task\n"));
+					goto error;
 				}
+				flags |= PFM_REGFL_OVFL_NOTIFY;
+			}
+
+			if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;
 
-				ctx->ctx_soft_pmds[cnum].flags |= PFM_REGFL_OVFL_NOTIFY;
+			/* verify validity of reset_pmds */
+			if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) {
+				DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));
+				goto error;
 			}
-			/*
-			 * copy reset vector
-			 */
-			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = tmp.reg_reset_pmds[0];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
+		} else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
+				DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum));
+				goto error;
 		}
+
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
+		if (PMC_WR_FUNC(cnum)) {
+			ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs);
+			if (ret) goto error;
+			ret = -EINVAL;
+		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		/*
 		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 *
+		 * If this fails, then the software state is not modified
 		 */
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * Now we commit the changes to the software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
-		}
 
 		/* 
-		 * We can proceed with this register!
+		 * full flag update each time a register is programmed
 		 */
+		ctx->ctx_soft_pmds[cnum].flags = flags;
+
+		if (PMC_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds;
+
+			/* mark all PMDS to be accessed as used */
+			CTX_USED_PMD(ctx, reset_pmds);
+		}
 
 		/*
 		 * Needed in case the user does not initialize the equivalent
@@ -1349,16 +1447,26 @@
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
-		th->pmc[cnum] = tmp.reg_value;
+		th->pmc[cnum] = value;
 
-		ia64_set_pmc(cnum, tmp.reg_value);
+		ia64_set_pmc(cnum, value);
 
 		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
-			  task->pid, cnum, tmp.reg_value, 
+			  task->pid, cnum, value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
 			  ctx->ctx_used_pmds[0]));
 
 	}
+
+	return 0;
+
+error:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1366,85 +1474,110 @@
 pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned long value, hw_value;
 	unsigned int cnum;
 	int i;
-	int ret = 0, reg_retval = 0;
-
-	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	int ret = 0;
 
 	/* 
 	 * Cannot do anything before PMU is enabled 
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-
 	/* XXX: ctx locking may be required here */
 
+	ret = -EINVAL;
+
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum  = tmp.reg_num;
+		value = tmp.reg_value;
 
-		cnum = tmp.reg_num;
 		if (!PMD_IS_IMPL(cnum)) {
-			ret = -EINVAL;
+			DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum));
 			goto abort_mission;
 		}
 
-		/* update virtualized (64bits) counter */
-		if (PMD_IS_COUNTING(cnum)) {
-			ctx->ctx_soft_pmds[cnum].ival = tmp.reg_value;
-			ctx->ctx_soft_pmds[cnum].val  = tmp.reg_value & ~pmu_conf.perf_ovfl_val;
-			ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset;
-			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
-
-		}
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
-
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		if (PMD_WR_FUNC(cnum)) {
+			unsigned long v = value;
+			ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs);
+			if (ret) goto abort_mission;
+			value = v;
+			ret = -EINVAL;
+		}
+		hw_value = value;
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * now commit changes to software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
+
+		/* update virtualized (64bits) counter */
+		if (PMD_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].lval = value;
+			ctx->ctx_soft_pmds[cnum].val  = value & ~pmu_conf.ovfl_val;
+
+			hw_value = value & pmu_conf.ovfl_val;
+
+			ctx->ctx_soft_pmds[cnum].long_reset  = tmp.reg_long_reset;
+			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
+
+			ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed;
+			ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask;
 		}
 
 		/* keep track of what we use */
 		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+
 		/* mark this register as used as well */
 		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
+		ia64_set_pmd(cnum, hw_value);
 
 		/* to go away */
 		ia64_srlz_d();
 
-		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
+		DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
 				task->pid, cnum,
+				value, hw_value,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
-				ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val,
+				ia64_get_pmd(cnum) & pmu_conf.ovfl_val,
 				PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',
 				ctx->ctx_used_pmds[0],
 				ctx->ctx_soft_pmds[cnum].reset_pmds[0]));
 	}
+
+	return 0;
+
+abort_mission:
+	/*
+	 * for now, we have only one possibility for error
+	 */
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	/*
+	 * we change the return value to EFAULT in case we cannot write register return code.
+	 * The caller first must correct this error, then a resubmission of the request will
+	 * eventually yield the EINVAL.
+	 */
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1452,10 +1585,13 @@
 pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	struct thread_struct *th = &task->thread;
-	unsigned long val=0;
-	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long val, lval;
+	pfarg_reg_t *req = (pfarg_reg_t *)arg;
+	unsigned int cnum, reg_flags = 0;
 	int i, ret = 0;
+#if __GNUC__ < 3
+	int foo;
+#endif
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1471,11 +1607,17 @@
 	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long ctx_val = ~0UL;
-
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		cnum = tmp.reg_num;
+#if __GNUC__ < 3
+		foo = __get_user(cnum, &req->reg_num);
+		if (foo) return -EFAULT;
+		foo = __get_user(reg_flags, &req->reg_flags);
+		if (foo) return -EFAULT;
+#else
+		if (__get_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT;
+#endif
+		lval = 0UL;
 
 		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
 		/*
@@ -1523,36 +1665,47 @@
 			/*
 			 * XXX: need to check for overflow
 			 */
+			val &= pmu_conf.ovfl_val;
+			val += ctx->ctx_soft_pmds[cnum].val;
 
-			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
+			lval = ctx->ctx_soft_pmds[cnum].lval;
 		} 
 
-		tmp.reg_value = val;
-
 		/*
 		 * execute read checker, if any
 		 */
 		if (PMD_RD_FUNC(cnum)) {
-			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
+			unsigned long v = val;
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs);
+			val = v;
 		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+		PFM_REG_RETFLAG_SET(reg_flags, ret);
 
 		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
 					cnum, ret, val, ia64_get_pmc(cnum)));
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		/*
+		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 */
+		if (__put_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__put_user(val, &req->reg_value)) return -EFAULT;
+		if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT;
+		if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT;
 	}
+
 	return 0;
+
 abort_mission:
-	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
 	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	__put_user(reg_flags, &req->reg_flags);
 
+	return -EINVAL;
 }
 
 #ifdef PFM_PMU_USES_DBR
@@ -1594,7 +1747,7 @@
 	else
 		pfm_sessions.pfs_ptrace_use_dbregs++;
 
-	DBprintk(("ptrace_use_dbregs=%lu  sys_use_dbregs=%lu by [%d] ret = %d\n", 
+	DBprintk(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n", 
 		  pfm_sessions.pfs_ptrace_use_dbregs, 
 		  pfm_sessions.pfs_sys_use_dbregs, 
 		  task->pid, ret));
@@ -1660,9 +1813,12 @@
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
 	if (task == current) {
-		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+		DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", 
+			task->pid, 
+			ctx->ctx_fl_frozen,
+			ctx->ctx_ovfl_regs[0]));
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -1721,44 +1877,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_SMP
-/*
- * On UP kernels, we do not need to constantly set the psr.pp bit
- * when a task is scheduled. The psr.pp bit can only be changed in
- * the kernel because of a user request. Given we are on a UP non preeemptive 
- * kernel we know that no other task is running, so we cna simply update their
- * psr.pp from their saved state. There is this no impact on the context switch
- * code compared to the SMP case.
- */
-static void
-pfm_tasklist_toggle_pp(unsigned int val)
-{
-	struct task_struct *p;
-	struct pt_regs *regs;
-
-	DBprintk(("invoked by [%d] pp=%u\n", current->pid, val));
-
-	read_lock(&tasklist_lock);
-
-	for_each_task(p) {
-       		regs = (struct pt_regs *)((unsigned long) p + IA64_STK_OFFSET);
-
-		/*
-		 * position on pt_regs saved on stack on 1st entry into the kernel
-		 */
-		regs--;
-
-		/*
-		 * update psr.pp
-		 */
-		ia64_psr(regs)->pp = val;
-	}
-	read_unlock(&tasklist_lock);
-}
-#endif
-
-
-
 static int
 pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
@@ -1787,11 +1905,8 @@
 
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+
 		ia64_psr(regs)->pp = 0;
 
 	} else {
@@ -1960,14 +2075,9 @@
 	int i, ret = 0;
 
 	/*
-	 * for range restriction: psr.db must be cleared or the
-	 * the PMU will ignore the debug registers.
-	 *
-	 * XXX: may need more in system wide mode,
-	 * no task can have this bit set?
+	 * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w
+	 * ensuring that no real breakpoint can be installed via this call.
 	 */
-	if (ia64_psr(regs)->db == 1) return -EINVAL;
-
 
 	first_time = ctx->ctx_fl_using_dbreg == 0;
 
@@ -2036,9 +2146,8 @@
 	 * Now install the values into the registers
 	 */
 	for (i = 0; i < count; i++, req++) {
-
 		
-		if (copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
 		
 		rnum      = tmp.dbreg_num;
 		dbreg.val = tmp.dbreg_value;
@@ -2071,7 +2180,7 @@
 
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
 
 		/*
 		 * Debug registers, just like PMC, can only be modified
@@ -2126,7 +2235,7 @@
 		 * XXX: for now we can only come here on EINVAL
 		 */
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL);
-		copy_to_user(req, &tmp, sizeof(tmp));
+		if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT;
 	}
 	return ret;
 }
@@ -2167,7 +2276,7 @@
 	tmp.ft_version      = PFM_VERSION;
 	tmp.ft_smpl_version = PFM_SMPL_VERSION;
 
-	if (copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
+	if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
 
 	return 0;
 }
@@ -2196,11 +2305,8 @@
 
 	if (ctx->ctx_fl_system) {
 		
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_dcr_pp  = 1;
-#else
-		pfm_tasklist_toggle_pp(1);
-#endif
+
 		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
@@ -2240,7 +2346,7 @@
 		pfm_lazy_save_regs(PMU_OWNER());
 
 	/* reset all registers to stable quiet state */
-	ia64_reset_pmu(task);
+	pfm_reset_pmu(task);
 
 	/* make sure nothing starts */
 	if (ctx->ctx_fl_system) {
@@ -2251,10 +2357,8 @@
 		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 1;
 		local_cpu_data->pfm_dcr_pp    = 0;
-#endif
+		local_cpu_data->pfm_syst_wide = 1;
 	} else {
 		/*
 		 * needed in case the task was a passive task during
@@ -2295,32 +2399,30 @@
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
-	int i;
+	int i, ret = -EINVAL;
 
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
 
 		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
 
-		tmp.reg_value = reset_pmcs[cnum];
+		tmp.reg_value = PMC_DFL_VAL(cnum);
 
 		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
 	return 0;
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
-	/* 
-	 * XXX: if this fails, we stick with the original failure, flag not updated!
-	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT;
+
+	return ret;
 }
 
 /*
@@ -2328,21 +2430,21 @@
  */
 static pfm_cmd_desc_t pfm_cmd_tab[]={
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
-/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
-/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)},
 /* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
+/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
 /* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2360,8 +2462,8 @@
 /* 30 */{ NULL, 0, 0, 0}, /* not used */
 /* 31 */{ NULL, 0, 0, 0}, /* not used */
 #ifdef PFM_PMU_USES_DBR
-/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
-/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
+/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
+/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
 #endif
 };
 #define PFM_CMD_COUNT	(sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
@@ -2383,7 +2485,10 @@
 		task_unlock(task);
 
 		do {
-			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
+			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) {
+				DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state));
+				return -EBUSY;
+			}
 			barrier();
 			cpu_relax();
 		} while (task_has_cpu(task));
@@ -2426,7 +2531,7 @@
 
 	if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT;
 
-	if (PFM_CMD_WRITE_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
+	if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
 
 	if (PFM_CMD_USE_PID(cmd))  {
 		/* 
@@ -2484,15 +2589,9 @@
 	return ret;
 }
 
-#if __GNUC__ >= 3
-void asmlinkage
-pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
-		      u64 arg6, u64 arg7, long info)
-#else
 void asmlinkage
 pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
 		      u64 arg6, u64 arg7, long info)
-#endif
 {
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
@@ -2537,7 +2636,7 @@
 		 * use the local reference
 		 */
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -2596,8 +2695,8 @@
 	 */
 	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
-	h->rate = 0; /* XXX: add the sampling rate used here */
-	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
+	h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL;
+	h->ip   = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL;
 	h->regs = ovfl_mask; 			/* which registers overflowed */
 
 	/* guaranteed to monotonically increase on each cpu */
@@ -2617,15 +2716,13 @@
 
 		if (PMD_IS_COUNTING(j)) {
 			*e  =  pfm_read_soft_counter(ctx, j);
-			/* check if this pmd overflowed as well */
-			*e +=  ovfl_mask & (1UL<<j) ? 1 + pmu_conf.perf_ovfl_val : 0;
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
 		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
-	pfm_stats.pfm_recorded_samples_count++;
+	pfm_stats[smp_processor_id()].pfm_recorded_samples_count++;
 
 	/*
 	 * make the new entry visible to user, needs to be atomic
@@ -2642,7 +2739,7 @@
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
-		pfm_stats.pfm_full_smpl_buffer_count++;
+		pfm_stats[smp_processor_id()].pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2719,23 +2816,13 @@
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
-		 * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use
-		 * val to count the number of times we overflowed. Otherwise we would loose the 
-		 * current value in the PMD (which can be >0). So to make sure we don't loose
-		 * the residual counts we set val to contain full 64bits value of the counter.
+		 * Note that the pmd is not necessarily 0 at this point as qualified events
+		 * may have happened before the PMU was frozen. The residual count is not
+		 * taken into consideration here but will be with any read of the pmd via
+		 * pfm_read_pmds().
 		 */
 		old_val = ctx->ctx_soft_pmds[i].val;
-		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
-
-		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
-			  i, ctx->ctx_soft_pmds[i].val, old_val, 
-			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
-
-		/*
-		 * now that we have extracted the hardware counter, we can clear it to ensure
-		 * that a subsequent PFM_READ_PMDS will not include it again.
-		 */
-		ia64_set_pmd(i, 0UL);
+		ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 
 		/*
 		 * check for overflow condition
@@ -2744,12 +2831,13 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
-
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
 			}
 		}
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", 
+			  i, ctx->ctx_soft_pmds[i].val, old_val, 
+			  ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify));
 	}
 
 	/*
@@ -2784,7 +2872,7 @@
 	 */
 	if (ovfl_notify == 0UL) {
 		if (ovfl_pmds) 
-			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2932,13 +3020,21 @@
 }
 
 static void
-perfmon_interrupt (int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
 {
 	u64 pmc0;
 	struct task_struct *task;
 	pfm_context_t *ctx;
 
-	pfm_stats.pfm_ovfl_intr_count++;
+	pfm_stats[smp_processor_id()].pfm_ovfl_intr_count++;
+
+	/*
+	 * if an alternate handler is registered, just bypass the default one
+	 */
+	if (pfm_alternate_intr_handler) {
+		(*pfm_alternate_intr_handler->handler)(irq, arg, regs);
+		return;
+	}
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2996,42 +3092,37 @@
 		atomic_set(&ctx->ctx_is_busy, 0);
 #endif
 	} else {
-		pfm_stats.pfm_spurious_ovfl_intr_count++;
-
-		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER());
+		pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++;
 	}
 }
 
 /* for debug only */
 static int
-perfmon_proc_info(char *page)
+pfm_proc_info(char *page)
 {
 	char *p = page;
 	int i;
 
-	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
-	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
-	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
-	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
+	p += sprintf(p, "fastctxsw              : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask              : 0x%lx\n", pmu_conf.ovfl_val);
 
-#ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d syst_wide   : %d\n"
-			"CPU%d dcr_pp      : %d\n", 
-			smp_processor_id(), 
-			local_cpu_data->pfm_syst_wide, 
-			smp_processor_id(), 
-			local_cpu_data->pfm_dcr_pp);
-#endif
+	for(i=0; i < NR_CPUS; i++) {
+		if (cpu_is_online(i) == 0) continue;
+		p += sprintf(p, "CPU%-2d overflow intrs   : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d spurious intrs   : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
+		p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count);
+		p += sprintf(p, "CPU%-2d syst_wide        : %d\n", i, cpu_data(i)->pfm_syst_wide);
+		p += sprintf(p, "CPU%-2d dcr_pp           : %d\n", i, cpu_data(i)->pfm_dcr_pp);
+		p += sprintf(p, "CPU%-2d owner            : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
+	}
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions    : %lu\n"
-			"sys_sessions     : %lu\n"
-			"sys_use_dbregs   : %lu\n"
-			"ptrace_use_dbregs: %lu\n", 
+
+	p += sprintf(p, "proc_sessions          : %u\n"
+			"sys_sessions           : %u\n"
+			"sys_use_dbregs         : %u\n"
+			"ptrace_use_dbregs      : %u\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -3039,30 +3130,6 @@
 
 	UNLOCK_PFS();
 
-	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d owner : %-6d\n",
-					i, 
-					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
-		}
-	}
-
-	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
-				i,
-				pmd_desc[i].type, 
-				pmd_desc[i].dep_pmd[0], 
-				pmd_desc[i].dep_pmc[0]); 
-	}
-
-	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
-				i, 
-				pmc_desc[i].type, 
-				pmc_desc[i].dep_pmd[0], 
-				pmc_desc[i].dep_pmc[0]); 
-	}
-
 	return p - page;
 }
 
@@ -3070,7 +3137,7 @@
 static int
 perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	int len = perfmon_proc_info(page);
+	int len = pfm_proc_info(page);
 
 	if (len <= off+count) *eof = 1;
 
@@ -3083,7 +3150,6 @@
 	return len;
 }
 
-#ifdef CONFIG_SMP
 void
 pfm_syst_wide_update_task(struct task_struct *task, int mode)
 {
@@ -3096,8 +3162,6 @@
 	 */
 	ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0;
 }
-#endif
-
 
 void
 pfm_save_regs (struct task_struct *task)
@@ -3409,7 +3473,7 @@
 	 */
 	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val);
 	}
 
 	/* 
@@ -3452,15 +3516,14 @@
  * XXX: make this routine able to work with non current context
  */
 static void
-ia64_reset_pmu(struct task_struct *task)
+pfm_reset_pmu(struct task_struct *task)
 {
 	struct thread_struct *t = &task->thread;
 	pfm_context_t *ctx = t->pfm_context;
-	unsigned long mask;
 	int i;
 
 	if (task != current) {
-		printk("perfmon: invalid task in ia64_reset_pmu()\n");
+		printk("perfmon: invalid task in pfm_reset_pmu()\n");
 		return;
 	}
 
@@ -3471,28 +3534,24 @@
 	 * install reset values for PMC. We skip PMC0 (done above)
 	 * XX: good up to 64 PMCS
 	 */
-	mask = pmu_conf.impl_regs[0] >> 1;
-	for(i=1; mask; mask>>=1, i++) {
-		if (mask & 0x1) {
-			ia64_set_pmc(i, reset_pmcs[i]);
-			/*
-			 * When restoring context, we must restore ALL pmcs, even the ones 
-			 * that the task does not use to avoid leaks and possibly corruption
-			 * of the sesion because of configuration conflicts. So here, we 
-			 * initialize the entire set used in the context switch restore routine.
-	 		 */
-			t->pmc[i] = reset_pmcs[i];
-			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
-						 
-		}
+	for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+		/*
+		 * When restoring context, we must restore ALL pmcs, even the ones 
+		 * that the task does not use to avoid leaks and possibly corruption
+		 * of the sesion because of configuration conflicts. So here, we 
+		 * initialize the entire set used in the context switch restore routine.
+	 	 */
+		t->pmc[i] = PMC_DFL_VAL(i);
+		DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i]));
 	}
 	/*
 	 * clear reset values for PMD. 
-	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
 	 */
-	mask = pmu_conf.impl_regs[4];
-	for(i=0; mask; mask>>=1, i++) {
-		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+	for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmd(i, 0UL);
 		t->pmd[i] = 0UL;
 	}
 
@@ -3521,13 +3580,13 @@
 	  *
 	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1;
 	/*
 	 * We must include all the PMD in this mask to avoid picking
 	 * up stale value and leak information, especially directly
 	 * at the user level when psr.sp=0
 	 */
-	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0];
 
 	/* 
 	 * Keep track of the pmds we want to sample
@@ -3537,7 +3596,7 @@
 	 *
 	 * We ignore the unimplemented pmds specified by the user
 	 */
-	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0];
 	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
@@ -3595,12 +3654,8 @@
 
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
 		local_cpu_data->pfm_syst_wide = 0;
 		local_cpu_data->pfm_dcr_pp    = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
 	} else  {
 
 		/* stop monitoring */
@@ -3670,10 +3725,14 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
+			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", 
+				task->pid, 
+				i, 
+				ctx->ctx_soft_pmds[i].val, 
+				val & pmu_conf.ovfl_val));
 
 			/* collect latest results */
-			ctx->ctx_soft_pmds[i].val += val & pmu_conf.perf_ovfl_val;
+			ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val;
 
 			/*
 			 * now everything is in ctx_soft_pmds[] and we need
@@ -3686,7 +3745,7 @@
 			 * take care of overflow inline
 			 */
 			if (pmc0 & (1UL << i)) {
-				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
+				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
@@ -3820,18 +3879,13 @@
 	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
 		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
-			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val;
+		} else {
+			thread->pmd[i]	      	   = 0UL; /* reset to initial state */
 		}
-		/* what about the other pmds? zero or keep as is */
 
 	}
-	/*
-	 * clear BTB index register
-	 * XXX: CPU-model specific knowledge!
-	 */
-	thread->pmd[16] = 0;
-
 
 	nctx->ctx_fl_frozen    = 0;
 	nctx->ctx_ovfl_regs[0] = 0UL;
@@ -3994,31 +4048,15 @@
 
 	UNLOCK_CTX(ctx);
 
-	LOCK_PFS();
+	pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu);
 
 	if (ctx->ctx_fl_system) {
-
-		pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-		DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu));
-
-		/* update perfmon debug register usage counter */
-		if (ctx->ctx_fl_using_dbreg) {
-			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
-				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
-			} else
-				pfm_sessions.pfs_sys_use_dbregs--;
-		}
-
 		/*
 	 	 * remove any CPU pinning
 	 	 */
 		task->cpus_allowed = ctx->ctx_saved_cpus_allowed;
 		task->need_resched = 1;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
-	UNLOCK_PFS();
+	} 
 
 	pfm_context_free(ctx);
 	/* 
@@ -4178,120 +4216,161 @@
 }
 
 static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
+	handler:	pfm_interrupt_handler,
 	flags:		SA_INTERRUPT,
 	name:		"perfmon"
 };
 
-
-static void
-pfm_pmu_snapshot(void)
+int
+pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
 {
-	int i;
+	int ret;
 
-	for (i=0; i < IA64_NUM_PMC_REGS; i++) {
-		if (i >= pmu_conf.num_pmcs) break;
-		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
+	/* some sanity checks */
+	if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
+
+	/* do the easy test first */
+	if (pfm_alternate_intr_handler) return -EBUSY;
+
+	/* reserve our session */
+	ret = pfm_reserve_session(NULL, 1, cpu_online_map);
+	if (ret) return ret;
+
+	if (pfm_alternate_intr_handler) {
+		printk("perfmon: install_alternate, intr_handler not NULL after reserve\n");
+		return -EINVAL;
 	}
-#ifdef CONFIG_MCKINLEY
-	/*
-	 * set the 'stupid' enable bit to power the PMU!
+
+	pfm_alternate_intr_handler = hdl;
+
+	return 0;
+}
+
+int
+pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
+{
+	if (hdl == NULL) return -EINVAL;
+
+	/* cannot remove someone else's handler! */
+	if (pfm_alternate_intr_handler != hdl) return -EINVAL;
+
+	pfm_alternate_intr_handler = NULL;
+
+	/* 
+	 * XXX: assume cpu_online_map has not changed since reservation 
 	 */
-	reset_pmcs[4] |= 1UL << 23;
-#endif
+	pfm_unreserve_session(NULL, 1, cpu_online_map);
+
+	return 0;
 }
 
 /*
  * perfmon initialization routine, called from the initcall() table
  */
 int __init
-perfmon_init (void)
+pfm_init(void)
 {
-	pal_perf_mon_info_u_t pm_info;
-	s64 status;
+	unsigned int n, n_counters, i;
 
-	pmu_conf.pfm_is_disabled = 1;
+	pmu_conf.disabled = 1;
 
-	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
+	printk("perfmon: version %u.%u IRQ %u\n", 
 		PFM_VERSION_MAJ, 
 		PFM_VERSION_MIN, 
-		PFM_SMPL_VERSION_MAJ, 
-		PFM_SMPL_VERSION_MIN, 
 		IA64_PERFMON_VECTOR);
 
-	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
-		printk("perfmon: PAL call failed (%ld), perfmon disabled\n", status);
-		return -1;
-	}
-
-	pmu_conf.perf_ovfl_val = (1UL << pm_info.pal_perf_mon_info_s.width) - 1;
-	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
-	pmu_conf.num_pmcs      = find_num_pm_regs(pmu_conf.impl_regs);
-	pmu_conf.num_pmds      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
-
-	printk("perfmon: %u bits counters\n", pm_info.pal_perf_mon_info_s.width);
-
-	printk("perfmon: %lu PMC/PMD pairs, %lu PMCs, %lu PMDs\n", 
-	       pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
+	/*
+	 * compute the number of implemented PMD/PMC from the
+	 * description tables
+	 */
+	n = 0;
+	for (i=0; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63);
+		n++;
+	}
+	pmu_conf.num_pmcs = n;
+
+	n = 0; n_counters = 0;
+	for (i=0; PMD_IS_LAST(i) == 0;  i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63);
+		n++;
+		if (PMD_IS_COUNTING(i)) n_counters++;
+	}
+	pmu_conf.num_pmds      = n;
+	pmu_conf.num_counters  = n_counters;
+
+	printk("perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", 
+	       pmu_conf.num_pmcs, 
+	       pmu_conf.num_pmds,
+	       pmu_conf.num_counters,
+	       ffz(pmu_conf.ovfl_val));
 
 	/* sanity check */
 	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
-		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon is DISABLED\n");
-		return -1; /* no need to continue anyway */
-	}
-
-	if (ia64_pal_debug_info(&pmu_conf.num_ibrs, &pmu_conf.num_dbrs)) {
-		printk(KERN_WARNING "perfmon: unable to get number of debug registers\n");
-		pmu_conf.num_ibrs = pmu_conf.num_dbrs = 0;
+		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
+		return -1;
 	}
-	/* PAL reports the number of pairs */
-	pmu_conf.num_ibrs <<=1;
-	pmu_conf.num_dbrs <<=1;
 
 	/*
-	 * take a snapshot of all PMU registers. PAL is supposed
-	 * to configure them with stable/safe values, i.e., not
-	 * capturing anything.
-	 * We take a snapshot now, before we make any modifications. This
-	 * will become our master copy. Then we will reuse the snapshot
-	 * to reset the PMU in pfm_enable(). Using this technique, perfmon
-	 * does NOT have to know about the specific values to program for
-	 * the PMC/PMD. The safe values may be different from one CPU model to
-	 * the other.
+	 * for now here for debug purposes
 	 */
-	pfm_pmu_snapshot();
+	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
+	if (perfmon_dir == NULL) {
+		printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
+		return -1; 
+	}
 
 	/*
-	 * setup the register configuration descriptions for the CPU
+	 * create /proc/perfmon
 	 */
-	pmu_conf.pmc_desc = pmc_desc;
-	pmu_conf.pmd_desc = pmd_desc;
-
-	/* we are all set */
-	pmu_conf.pfm_is_disabled = 0;
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
 
 	/*
-	 * for now here for debug purposes
+	 * initialize all our spinlocks
 	 */
-	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
-
-	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
-
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
+	/* we are all set */
+	pmu_conf.disabled = 0;
+
 	return 0;
 }
 
-__initcall(perfmon_init);
+__initcall(pfm_init);
 
 void
-perfmon_init_percpu (void)
+pfm_init_percpu(void)
 {
+	int i;
+
 	if (smp_processor_id() == 0)
 		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
 
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
+
+	/*
+	 * we first initialize the PMU to a stable state.
+	 * the values may have been changed from their power-up
+	 * values by software executed before the kernel took over.
+	 *
+	 * At this point, pmu_conf has not yet been initialized
+	 *
+	 * On McKinley, this code is ineffective until PMC4 is initialized.
+	 */
+	for (i=1; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+	}
+
+	for (i=0; PMD_IS_LAST(i); i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		ia64_set_pmd(i, 0UL);
+	}
+	ia64_set_pmc(0,1UL);
+	ia64_srlz_d();
 }
 
 #else /* !CONFIG_PERFMON */
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/perfmon_generic.h linux-2.4.21-pre2/arch/ia64/kernel/perfmon_generic.h
--- linux-2.4.21-pre1/arch/ia64/kernel/perfmon_generic.h	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/perfmon_generic.h	Wed Dec 18 14:16:26 2002
@@ -1,29 +1,48 @@
+/*
+ * This file contains the architected PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
 #define RDEP(x)	(1UL<<(x))
 
-#ifdef CONFIG_ITANIUM
-#error "This file should not be used when CONFIG_ITANIUM is defined"
+#if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY)
+#error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined"
 #endif
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd1  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd2  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd3  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd1  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd2  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd3  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_gen_pmd_desc,
+	pmc_desc:	pfm_gen_pmc_desc
 };
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/perfmon_itanium.h linux-2.4.21-pre2/arch/ia64/kernel/perfmon_itanium.h
--- linux-2.4.21-pre1/arch/ia64/kernel/perfmon_itanium.h	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/perfmon_itanium.h	Wed Dec 18 14:16:26 2002
@@ -15,46 +15,59 @@
 static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_ita_pmd_desc,
+	pmc_desc:	pfm_ita_pmc_desc
+};
+
+
 static int
 pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.21-pre2/arch/ia64/kernel/perfmon_mckinley.h
--- linux-2.4.21-pre1/arch/ia64/kernel/perfmon_mckinley.h	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/perfmon_mckinley.h	Wed Dec 18 14:16:26 2002
@@ -12,51 +12,86 @@
 #error "This file is only valid when CONFIG_MCKINLEY is defined"
 #endif
 
+static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL,  pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL,  pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG  , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG  , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 47) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_mck_pmd_desc,
+	pmc_desc:	pfm_mck_pmc_desc
+};
+
+
+/*
+ * PMC reserved fields must have their power-up values preserved
+ */
+static int
+pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	unsigned long tmp1, tmp2, ival = *val;
+
+	/* remove reserved areas from user value */
+	tmp1 = ival & PMC_RSVD_MASK(cnum);
+
+	/* get reserved fields values */
+	tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+
+	*val = tmp1 | tmp2;
+
+	DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", 
+		  cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); 
+	return 0;
+}
+
 static int
 pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
@@ -65,6 +100,9 @@
 	int ret = 0, check_case1 = 0;
 	unsigned long val8 = 0, val14 = 0, val13 = 0;
 
+	/* first preserve the reserved fields */
+	pfm_mck_reserved(task, cnum, val, regs);
+
 	/*
 	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
 	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
@@ -105,8 +143,11 @@
 		case  8: val8 = *val;
 			 val13 = th->pmc[13];
 			 val14 = th->pmc[14];
+			 *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 check_case1 = 1;
 			 break;
+		case  9: *val |= 1UL << 2; /* bit 2 must always be 1 */
+			 break;
 		case 13: val8  = th->pmc[8];
 			 val13 = *val;
 			 val14 = th->pmc[14];
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/process.c linux-2.4.21-pre2/arch/ia64/kernel/process.c
--- linux-2.4.21-pre1/arch/ia64/kernel/process.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/process.c	Wed Dec 18 14:16:26 2002
@@ -168,10 +168,8 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_save_regs(task);
 
-# ifdef CONFIG_SMP
 	if (local_cpu_data->pfm_syst_wide)
 		pfm_syst_wide_update_task(task, 0);
-# endif
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -190,10 +188,8 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_load_regs(task);
 
-# ifdef CONFIG_SMP
 	if (local_cpu_data->pfm_syst_wide)
 		pfm_syst_wide_update_task(task, 1);
-# endif
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/ptrace.c linux-2.4.21-pre2/arch/ia64/kernel/ptrace.c
--- linux-2.4.21-pre1/arch/ia64/kernel/ptrace.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/ptrace.c	Wed Dec 18 14:16:26 2002
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
@@ -459,6 +460,60 @@
 	pt->loadrs = 0;
 }
 
+static inline void
+sync_user_rbs_one_thread (struct task_struct *p, int make_writable)
+{
+	struct switch_stack *sw;
+	unsigned long urbs_end;
+	struct pt_regs *pt;
+
+	sw = (struct switch_stack *) (p->thread.ksp + 16);
+	pt = ia64_task_regs(p);
+	urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
+	ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
+	if (make_writable)
+		user_flushrs(p, pt);
+}
+
+struct task_list {
+	struct task_list *next;
+	struct task_struct *task;
+};
+
+#ifdef CONFIG_SMP
+
+static inline void
+collect_task (struct task_list **listp, struct task_struct *p, int make_writable)
+{
+	struct task_list *e;
+
+	e = kmalloc(sizeof(*e), GFP_KERNEL);
+	if (!e)
+		/* oops, can't collect more: finish at least what we collected so far... */
+		return;
+
+	get_task_struct(p);
+	e->task = p;
+	e->next = *listp;
+	*listp = e;
+}
+
+static inline struct task_list *
+finish_task (struct task_list *list, int make_writable)
+{
+	struct task_list *next = list->next;
+
+	sync_user_rbs_one_thread(list->task, make_writable);
+	free_task_struct(list->task);
+	kfree(list);
+	return next;
+}
+
+#else
+# define collect_task(list, p, make_writable)	sync_user_rbs_one_thread(p, make_writable)
+# define finish_task(list, make_writable)	(NULL)
+#endif
+
 /*
  * Synchronize the RSE backing store of CHILD and all tasks that share the address space
  * with it.  CHILD_URBS_END is the address of the end of the register backing store of
@@ -472,7 +527,6 @@
 threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable)
 {
 	struct switch_stack *sw;
-	unsigned long urbs_end;
 	struct task_struct *p;
 	struct mm_struct *mm;
 	struct pt_regs *pt;
@@ -492,20 +546,27 @@
 		if (make_writable)
 			user_flushrs(child, pt);
 	} else {
+		/*
+		 * Note: we can't call ia64_sync_user_rbs() while holding the
+		 * tasklist_lock because that may cause a dead-lock: ia64_sync_user_rbs()
+		 * may indirectly call tlb_flush_all(), which triggers an IPI.
+		 * Furthermore, tasklist_lock is acquired by fork() with interrupts
+		 * disabled, so with the right timing, the IPI never completes, hence
+		 * tasklist_lock never gets released, hence fork() never completes...
+		 */
+		struct task_list *list = NULL;
+
 		read_lock(&tasklist_lock);
 		{
 			for_each_task(p) {
-				if (p->mm == mm && p->state != TASK_RUNNING) {
-					sw = (struct switch_stack *) (p->thread.ksp + 16);
-					pt = ia64_task_regs(p);
-					urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
-					ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
-					if (make_writable)
-						user_flushrs(p, pt);
-				}
+				if (p->mm == mm && p->state != TASK_RUNNING)
+					collect_task(&list, p, make_writable);
 			}
 		}
 		read_unlock(&tasklist_lock);
+
+		while (list)
+			list = finish_task(list, make_writable);
 	}
 	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;	/* set the flag in the child thread only */
 }
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/signal.c linux-2.4.21-pre2/arch/ia64/kernel/signal.c
--- linux-2.4.21-pre1/arch/ia64/kernel/signal.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/signal.c	Wed Dec 18 14:16:26 2002
@@ -41,6 +41,16 @@
 
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 long
 ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
 {
@@ -354,6 +364,15 @@
 	return err;
 }
 
+/*
+ * Check whether the register-backing store is already on the signal stack.
+ */
+static inline int
+rbs_on_sig_stack (unsigned long bsp)
+{
+	return (bsp - current->sas_ss_sp < current->sas_ss_size);
+}
+
 static long
 setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
 	     struct sigscratch *scr)
@@ -366,10 +385,16 @@
 
 	frame = (void *) scr->pt.r12;
 	tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
-	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) {
-		new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
+	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
 		frame = (void *) ((current->sas_ss_sp + current->sas_ss_size)
 				  & ~(STACK_ALIGN - 1));
+  		/*
+		 * We need to check for the register stack being on the signal stack
+		 * separately, because it's switched separately (memory stack is switched
+		 * in the kernel, register stack is switched in the signal trampoline).
+  		 */
+		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
+			new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
 	}
 	frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
 
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/smp.c linux-2.4.21-pre2/arch/ia64/kernel/smp.c
--- linux-2.4.21-pre1/arch/ia64/kernel/smp.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/smp.c	Wed Dec 18 14:16:26 2002
@@ -188,8 +188,20 @@
 void
 smp_flush_tlb_all (void)
 {
-	smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1);
-	__flush_tlb_all();
+	smp_call_function((void (*)(void *))local_flush_tlb_all, 0, 1, 1);
+	local_flush_tlb_all();
+}
+
+void
+smp_flush_tlb_mm (struct mm_struct *mm)
+{
+	local_flush_tlb_mm(mm);
+
+	/* this happens for the common case of a single-threaded fork():  */
+	if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
+		return;
+
+	smp_call_function((void (*)(void *))local_flush_tlb_mm, mm, 1, 1);
 }
 
 /*
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/smpboot.c linux-2.4.21-pre2/arch/ia64/kernel/smpboot.c
--- linux-2.4.21-pre1/arch/ia64/kernel/smpboot.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/smpboot.c	Wed Dec 18 14:16:26 2002
@@ -321,7 +321,7 @@
 	extern void ia64_init_itm(void);
 
 #ifdef CONFIG_PERFMON
-	extern void perfmon_init_percpu(void);
+	extern void pfm_init_percpu(void);
 #endif
 
 	cpuid = smp_processor_id();
@@ -356,7 +356,7 @@
 #endif
 
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 
 	local_irq_enable();
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/sys_ia64.c linux-2.4.21-pre2/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.21-pre1/arch/ia64/kernel/sys_ia64.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/sys_ia64.c	Wed Dec 18 14:16:26 2002
@@ -253,6 +253,29 @@
 	return addr;
 }
 
+asmlinkage unsigned long
+ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
+	     unsigned long new_addr)
+{
+	extern unsigned long do_mremap (unsigned long addr,
+					unsigned long old_len,
+					unsigned long new_len,
+					unsigned long flags,
+					unsigned long new_addr);
+
+	down_write(&current->mm->mmap_sem);
+	{
+		addr = do_mremap(addr, old_len, new_len, flags, new_addr);
+	}
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *) addr))
+		return addr;
+
+	force_successful_syscall_return();
+	return addr;
+}
+
 asmlinkage long
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/traps.c linux-2.4.21-pre2/arch/ia64/kernel/traps.c
--- linux-2.4.21-pre1/arch/ia64/kernel/traps.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/traps.c	Wed Dec 18 14:16:26 2002
@@ -142,7 +142,8 @@
 	siginfo.si_isr = 0;
 
 	switch (break_num) {
-	      case 0: /* unknown error */
+	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+		die_if_kernel("Bad break", regs, break_num);
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
diff -urN linux-2.4.21-pre1/arch/ia64/kernel/unaligned.c linux-2.4.21-pre2/arch/ia64/kernel/unaligned.c
--- linux-2.4.21-pre1/arch/ia64/kernel/unaligned.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/kernel/unaligned.c	Wed Dec 18 14:16:26 2002
@@ -5,6 +5,10 @@
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 2002/12/09   Fix rotating register handling (off-by-1 error, missing fr-rotation).  Fix
+ *		get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
+ *		stacked register returns an undefined value; it does NOT trigger a
+ *		"rsvd register fault").
  * 2001/10/11	Fix unaligned access to rotating registers in s/w pipelined loops.
  * 2001/08/13	Correct size of extended floats (float_fsz) from 16 to 10 bytes.
  * 2001/01/17	Add support emulation of unaligned kernel accesses.
@@ -275,6 +279,15 @@
 #	undef F
 }
 
+static inline unsigned long
+rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+	reg += rrb;
+	if (reg >= sor)
+		reg -= sor;
+	return reg;
+}
+
 static void
 set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
 {
@@ -286,26 +299,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
-
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
-
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) >= sof) {
+	if (ridx >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
 		DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
 		return;
 	}
 
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
+
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -333,7 +342,7 @@
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -367,26 +376,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
+	if (ridx >= sof) {
+		/* read of out-of-frame register returns an undefined value; 0 in our case.  */
+		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+		goto fail;
+	}
+
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
 
 	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
 	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
-	if ((r1 - 32) >= sof) {
-		/* this should never happen, as the "rsvd register fault" has higher priority */
-		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
-		return;
-	}
-
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		*val = *addr;
@@ -406,13 +411,13 @@
 	 */
 	if (regs->r12 >= TASK_SIZE) {
 		DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
-		return;
+		goto fail;
 	}
 
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -427,6 +432,13 @@
 		ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 		*nat = (rnats & nat_mask) != 0;
 	}
+	return;
+
+  fail:
+	*val = 0;
+	if (nat)
+		*nat = 0;
+	return;
 }
 
 
@@ -485,7 +497,16 @@
 	DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
 }
 
-#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
+/*
+ * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
+ * range from 32-127, result is in the range from 0-95.
+ */
+static inline unsigned long
+fph_index (struct pt_regs *regs, long regnum)
+{
+	unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+	return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
 
 static void
 setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
@@ -506,7 +527,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_sync_fph(current);
-		current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
+		current->thread.fph[fph_index(regs, regnum)] = *fpval;
 	} else {
 		/*
 		 * pt_regs or switch_stack ?
@@ -565,7 +586,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_flush_fph(current);
-		*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
+		*fpval = current->thread.fph[fph_index(regs, regnum)];
 	} else {
 		/*
 		 * f0 = 0.0, f1= 1.0. Those registers are constant and are thus
@@ -650,8 +671,8 @@
 	 * just in case.
 	 */
 	if (ld.x6_op == 1 || ld.x6_op == 3) {
-		printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
-		die_if_kernel("unaligned reference on specualtive load with register update\n",
+		printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
+		die_if_kernel("unaligned reference on speculative load with register update\n",
 			      regs, 30);
 	}
 
@@ -1080,8 +1101,8 @@
 		 * For this reason we keep this sanity check
 		 */
 		if (ld.x6_op == 1 || ld.x6_op == 3)
-			printk("%s %s: register update on speculative load pair, "
-			       "error\n",KERN_ERR, __FUNCTION__);
+			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+			       __FUNCTION__);
 
 		setreg(ld.r3, ifa, 0, regs);
 	}
diff -urN linux-2.4.21-pre1/arch/ia64/lib/Makefile linux-2.4.21-pre2/arch/ia64/lib/Makefile
--- linux-2.4.21-pre1/arch/ia64/lib/Makefile	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/lib/Makefile	Wed Dec 18 14:16:26 2002
@@ -11,7 +11,7 @@
 
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o					\
+	carta_random.o checksum.o clear_page.o csum_partial_copy.o					\
 	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o			\
 	flush.o ip_fast_csum.o io.o do_csum.o						\
 	memset.o strlen.o swiotlb.o
diff -urN linux-2.4.21-pre1/arch/ia64/lib/carta_random.S linux-2.4.21-pre2/arch/ia64/lib/carta_random.S
--- linux-2.4.21-pre1/arch/ia64/lib/carta_random.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/arch/ia64/lib/carta_random.S	Wed Dec 18 14:16:26 2002
@@ -0,0 +1,54 @@
+/*
+ * Fast, simple, yet decent quality random number generator based on
+ * a paper by David G. Carta ("Two Fast Implementations of the
+ * `Minimal Standard' Random Number Generator," Communications of the
+ * ACM, January, 1990).
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <asm/asmmacro.h>
+
+#define a	r2
+#define m	r3
+#define lo	r8
+#define hi	r9
+#define t0	r16
+#define t1	r17
+#define	seed	r32
+
+GLOBAL_ENTRY(carta_random32)
+	movl	a = (16807 << 16) | 16807
+	;;
+	pmpyshr2.u t0 = a, seed, 0
+	pmpyshr2.u t1 = a, seed, 16
+	;;
+	unpack2.l t0 = t1, t0
+	dep	m = -1, r0, 0, 31
+	;;
+	zxt4	lo = t0
+	shr.u	hi = t0, 32
+	;;
+	dep	t0 = 0, hi, 15, 49	// t0 = (hi & 0x7fff)
+	;;
+	shl	t0 = t0, 16		// t0 = (hi & 0x7fff) << 16
+	shr	t1 = hi, 15		// t1 = (hi >> 15)
+	;;
+	add	lo = lo, t0
+	;;
+	cmp.gtu	p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	;;
+	add	lo = lo, t1
+	;;
+	cmp.gtu p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	br.ret.sptk.many rp
+END(carta_random32)
diff -urN linux-2.4.21-pre1/arch/ia64/lib/memcpy_mck.S linux-2.4.21-pre2/arch/ia64/lib/memcpy_mck.S
--- linux-2.4.21-pre1/arch/ia64/lib/memcpy_mck.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/lib/memcpy_mck.S	Wed Dec 18 14:16:26 2002
@@ -6,7 +6,10 @@
  *	in1:	source address
  *	in2:	number of bytes to copy
  * Output:
- * 	0 if success, or number of byte NOT copied if error occurred.
+ *	for bcopy:     return nothing
+ *	for memcpy:    return dest
+ * 	for copy_user: 0 if success,
+ *		       or number of bytes NOT copied if error occurred.
  *
  * Copyright (C) 2002 Intel Corp.
  * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
@@ -21,15 +24,6 @@
 # define EK(y,x...)	x
 #endif
 
-GLOBAL_ENTRY(bcopy)
-	.regstk 3,0,0,0
-	mov r8=in0
-	mov in0=in1
-	;;
-	mov in1=r8
-	;;
-END(bcopy)
-
 /* McKinley specific optimization */
 
 #define retval		r8
@@ -82,10 +76,19 @@
 #define in1		r33
 #define in2		r34
 
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0		// swap the src and dest arguments
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)			// fall through to memcpy
 GLOBAL_ENTRY(memcpy)
 	and	r28=0x7,in0
 	and	r29=0x7,in1
 	mov	f6=f0
+	mov	retval=in0
 	br.cond.sptk .common_code
 	;;
 END(memcpy)
@@ -97,7 +100,7 @@
 	mov	f6=f1
 	mov	saved_in0=in0	// save dest pointer
 	mov	saved_in1=in1	// save src pointer
-	mov	saved_in2=in2	// save len
+	mov	retval=r0	// initialize return value
 	;;
 .common_code:
 	cmp.gt	p15,p0=8,in2	// check for small size
@@ -105,7 +108,7 @@
 	cmp.ne	p14,p0=0,r29	// check src alignment
 	add	src0=0,in1
 	sub	r30=8,r28	// for .align_dest
-	mov	retval=r0	// initialize return value
+	mov	saved_in2=in2	// save len
 	;;
 	add	dst0=0,in0
 	add	dst1=1,in0	// dest odd index
diff -urN linux-2.4.21-pre1/arch/ia64/lib/swiotlb.c linux-2.4.21-pre2/arch/ia64/lib/swiotlb.c
--- linux-2.4.21-pre1/arch/ia64/lib/swiotlb.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/lib/swiotlb.c	Wed Dec 18 14:16:26 2002
@@ -351,7 +351,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -417,23 +417,23 @@
 int
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
-	void *addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
-		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
-			if (sg->address)
-				sg->address = addr;
-			else {
-				sg->page = virt_to_page(addr);
-				sg->offset = (u64) addr & ~PAGE_MASK;
-			}
-		}
+		void * virt_address = SG_ENT_VIRT_ADDRESS(sg);
+		unsigned long phys_address = virt_to_phys(virt_address);
+
+		sg->dma_length = sg->length;
+		if (phys_address & ~hwdev->dma_mask)
+			sg->dma_address = virt_to_phys(map_single(hwdev,
+			                                          virt_address,
+			                                          sg->length,
+			                                          direction));
+		else
+			sg->dma_address = phys_address;
 	}
 	return nelems;
 }
@@ -451,14 +451,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
-			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-			if (sg->address)
-				sg->address = sg->orig_address;
-			else {
-				sg->page = virt_to_page(sg->orig_address);
-				sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
-			}
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg))) {
+			unmap_single(hwdev, phys_to_virt(sg->dma_address),
+			             sg->dma_length, direction);
 		} else if (direction == PCI_DMA_FROMDEVICE)
 			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
 }
@@ -479,14 +474,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
-			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-}
-
-unsigned long
-swiotlb_dma_address (struct scatterlist *sg)
-{
-	return SG_ENT_PHYS_ADDRESS(sg);
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg)))
+			sync_single(hwdev, phys_to_virt(sg->dma_address),
+			            sg->dma_length, direction);
 }
 
 /*
@@ -507,7 +497,6 @@
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 EXPORT_SYMBOL(swiotlb_sync_single);
 EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
 EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -urN linux-2.4.21-pre1/arch/ia64/mm/Makefile linux-2.4.21-pre2/arch/ia64/mm/Makefile
--- linux-2.4.21-pre1/arch/ia64/mm/Makefile	Thu Jan  4 12:50:17 2001
+++ linux-2.4.21-pre2/arch/ia64/mm/Makefile	Wed Dec 18 14:16:26 2002
@@ -9,6 +9,8 @@
 
 O_TARGET := mm.o
 
+export-objs := init.o
+
 obj-y	 := init.o fault.o tlb.o extable.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre1/arch/ia64/mm/fault.c linux-2.4.21-pre2/arch/ia64/mm/fault.c
--- linux-2.4.21-pre1/arch/ia64/mm/fault.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/mm/fault.c	Wed Dec 18 14:16:26 2002
@@ -58,7 +58,6 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 	/*
 	 * If fault is in region 5 and we are in the kernel, we may already
          * have the mmap_sem (VALID_PAGE macro is called during mmap). There
@@ -67,7 +66,6 @@
   	 */
 	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
 		goto bad_area_no_up;
-#endif
 
 	down_read(&mm->mmap_sem);
 
@@ -148,9 +146,7 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
-#ifdef CONFIG_VIRTUAL_MEM_MAP
   bad_area_no_up:
-#endif
 	if ((isr & IA64_ISR_SP)
 	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
 	{
diff -urN linux-2.4.21-pre1/arch/ia64/mm/init.c linux-2.4.21-pre2/arch/ia64/mm/init.c
--- linux-2.4.21-pre1/arch/ia64/mm/init.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/mm/init.c	Wed Dec 18 14:16:26 2002
@@ -5,6 +5,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 
@@ -35,15 +36,14 @@
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
+#define LARGE_GAP 0x40000000 /* Use virtual mem map if a hole is > than this */
 
 static unsigned long totalram_pages;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 unsigned long vmalloc_end = VMALLOC_END_INIT;
 
 static struct page *vmem_map;
 static unsigned long num_dma_physpages;
-#endif
 
 int
 do_check_pgt_cache (int low, int high)
@@ -114,8 +114,8 @@
 
 	addr = (unsigned long) &__init_begin;
 	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
-		clear_bit(PG_reserved, &virt_to_page(addr)->flags);
-		set_page_count(virt_to_page(addr), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)addr)->flags);
+		set_page_count(virt_to_page((void *)addr), 1);
 		free_page(addr);
 		++totalram_pages;
 	}
@@ -164,10 +164,10 @@
 		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
-		if (!VALID_PAGE(virt_to_page(start)))
+		if (!VALID_PAGE(virt_to_page((void *)start)))
 			continue;
-		clear_bit(PG_reserved, &virt_to_page(start)->flags);
-		set_page_count(virt_to_page(start), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)start)->flags);
+		set_page_count(virt_to_page((void *)start), 1);
 		free_page(start);
 		++totalram_pages;
 	}
@@ -357,10 +357,6 @@
 	ia64_tlb_init();
 }
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
-#include <asm/pgtable.h>
-
 static int
 create_mem_map_page_table (u64 start, u64 end, void *arg)
 {
@@ -413,8 +409,8 @@
 
 	/* Should we use platform_map_nr here? */
 
-	map_start = vmem_map + MAP_NR_DENSE(start);
-	map_end   = vmem_map + MAP_NR_DENSE(end);
+	map_start = mem_map + MAP_NR_DENSE(start);
+	map_end   = mem_map + MAP_NR_DENSE(end);
 
 	if (map_start < args->start)
 		map_start = args->start;
@@ -444,15 +440,19 @@
 arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start,
 	struct page *end, int zone, unsigned long start_paddr, int highmem)
 {
-	struct memmap_init_callback_data args;
+	if (!vmem_map) 
+		memmap_init(start,end,zone,page_to_phys(start),highmem);
+	else {
+		struct memmap_init_callback_data args;
 
-	args.memmap_init = memmap_init;
-	args.start = start;
-	args.end = end;
-	args.zone = zone;
-	args.highmem = highmem;
+		args.memmap_init = memmap_init;
+		args.start = start;
+		args.end = end;
+		args.zone = zone;
+		args.highmem = highmem;
 
-	efi_memmap_walk(virtual_memmap_init, &args);
+		efi_memmap_walk(virtual_memmap_init, &args);
+	}
 
 	return page_to_phys(end);
 }
@@ -475,8 +475,6 @@
 	return __get_user(byte, (char *) page) == 0;
 }
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 static int
 count_pages (u64 start, u64 end, void *arg)
 {
@@ -486,47 +484,75 @@
 	return 0;
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+static int
+find_largest_hole(u64 start, u64 end, void *arg)
+{
+	u64 *max_gap = arg;
+	static u64 last_end = PAGE_OFFSET;
+
+	/* NOTE: this algorithm assumes efi memmap table is ordered */
+
+	if (*max_gap < (start - last_end))
+		*max_gap = start - last_end;
+	last_end = end;
+	return 0;
+}
+#endif
+
 /*
  * Set up the page tables.
  */
 void
 paging_init (void)
 {
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+	unsigned long zholes_size[MAX_NR_ZONES];
+#ifndef CONFIG_DISCONTIGMEM
+	unsigned long max_gap;
+#endif
 
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
+	memset(zholes_size, 0, sizeof(zholes_size));
 
 	num_physpages = 0;
 	efi_memmap_walk(count_pages, &num_physpages);
 
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-	{
-		unsigned long zholes_size[MAX_NR_ZONES];
-		unsigned long map_size;
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-		memset(zholes_size, 0, sizeof(zholes_size));
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] = (max_low_pfn - max_dma)
+					- (num_physpages - num_dma_physpages);
+		}
+	}
 
-		num_dma_physpages = 0;
-		efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+#ifdef CONFIG_DISCONTIGMEM
+	free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+#else
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
 
-		if (max_low_pfn < max_dma) {
-			zones_size[ZONE_DMA] = max_low_pfn;
-			zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
-		} else {
-			zones_size[ZONE_DMA] = max_dma;
-			zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
-			if (num_physpages > num_dma_physpages) {
-				zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-				zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
-							    - (num_physpages - num_dma_physpages));
-			}
-		}
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *)0;
+		free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+	}
+	else {
+		unsigned long map_size;
 
-		/* allocate virtual mem_map: */
+		/* allocate virtual mem_map */
 
 		map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page));
 		vmalloc_end -= map_size;
@@ -536,15 +562,7 @@
 		free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size);
 		printk("Virtual mem_map starts at 0x%p\n", mem_map);
 	}
-#else /* !CONFIG_VIRTUAL_MEM_MAP */
-	if (max_low_pfn < max_dma)
-		zones_size[ZONE_DMA] = max_low_pfn;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-	}
-	free_area_init(zones_size);
-#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+#endif
 }
 
 static int
@@ -554,7 +572,7 @@
 	unsigned long *count = arg;
 	struct page *pg;
 
-	for (pg = virt_to_page(start); pg < virt_to_page(end); ++pg)
+	for (pg = virt_to_page((void *)start); pg < virt_to_page((void *)end); ++pg)
 		if (PageReserved(pg))
 			++num_reserved;
 	*count += num_reserved;
diff -urN linux-2.4.21-pre1/arch/ia64/mm/tlb.c linux-2.4.21-pre2/arch/ia64/mm/tlb.c
--- linux-2.4.21-pre1/arch/ia64/mm/tlb.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/mm/tlb.c	Wed Dec 18 14:16:26 2002
@@ -100,7 +100,7 @@
 }
 
 void
-__flush_tlb_all (void)
+local_flush_tlb_all (void)
 {
 	unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
 
@@ -185,5 +185,5 @@
 	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
 	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
-	__flush_tlb_all();		/* nuke left overs from bootstrapping... */
+	local_flush_tlb_all();		/* nuke left overs from bootstrapping... */
 }
diff -urN linux-2.4.21-pre1/arch/ia64/sn/io/pci_dma.c linux-2.4.21-pre2/arch/ia64/sn/io/pci_dma.c
--- linux-2.4.21-pre1/arch/ia64/sn/io/pci_dma.c	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/sn/io/pci_dma.c	Wed Dec 18 14:16:26 2002
@@ -309,7 +309,6 @@
 
 	int i;
 	devfs_handle_t vhdl;
-	dma_addr_t dma_addr;
 	unsigned long phys_addr;
 	struct sn_device_sysdata *device_sysdata;
 	pciio_dmamap_t dma_map;
@@ -333,34 +332,28 @@
                    attempt to map scatterlists that they have
                    previously mapped.  we print a warning and
                    continue, but the driver should be fixed */
-		switch (((u64)sg->address) >> 60) {
-		case 0xa:
-		case 0xb:
 #ifdef DEBUG
+		if (sg->dma_address) {
 /* This needs to be cleaned up at some point. */
 			NAG("A PCI driver (for device at%8s) has attempted to "
 			    "map a scatterlist that was previously mapped at "
 			    "%p - this is currently being worked around.\n",
-			    hwdev->slot_name, (void *)sg->address);
+			    hwdev->slot_name, (void *)sg->dma_address);
+			phys_addr = (u64)sg->dma_address & TO_PHYS_MASK;
+		} else
 #endif
-			phys_addr = (u64)sg->address & TO_PHYS_MASK;
-			break;
-		default: /* not previously mapped, get the phys. addr */
-			phys_addr = __pa(sg->address);
-			break;
-		}
-		sg->page = NULL;
-		dma_addr = 0;
+			phys_addr = __pa(sg->address ? sg->address :
+					page_address(sg->page) + offset);
 
 		/*
 		 * Handle the most common case: 64 bit cards.  This
 		 * call should always succeed.
 		 */
 		if (IS_PCIA64(hwdev)) {
-			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+			sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
 						       DMA_DATA_FLAGS | PCIIO_DMA_A64 );
-			sg->address = (char *)dma_addr;
+			sg->dma_length = sg->length;
 			continue;
 		}
 
@@ -368,16 +361,14 @@
 		 * Handle 32-63 bit cards via direct mapping
 		 */
 		if (IS_PCI32G(hwdev)) {
-			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
-						       sg->length,
-						       DMA_DATA_FLAGS);
-			/*
-			 * See if we got a direct map entry
-			 */
-			if (dma_addr) {
-				sg->address = (char *)dma_addr;
+			sg->dma_address = pciio_dmatrans_addr(vhdl, NULL,
+								phys_addr,
+								sg->length,
+								DMA_DATA_FLAGS);
+			sg->dma_length = sg->length;
+
+			if (sg->dma_address)
 				continue;
-			}
 
 		}
 
@@ -393,10 +384,10 @@
 			       "anymore 32 bit page map entries.\n");
 			BUG();
 		}
-		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
-		sg->address = (char *)dma_addr;
+		sg->dma_address = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
+		sg->dma_length = sg->length;
+#warning BADBADBAD scsi retries will die since sglist is unmapped and reused.
 		sg->page = (char *)dma_map;
-		
 	}
 
 	return nents;
@@ -418,19 +409,20 @@
 sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
 	int i;
-	struct sn_dma_maps_s *sn_dma_map;
 
 	/* can't go anywhere w/o a direction in life */
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nents; i++, sg++)
+#warning need to derive sn_dma_map from sg->dma_address instead
 		if (sg->page) {
+			struct sn_dma_maps_s *sn_dma_map;
 			/*
 			 * We maintain the DMA Map pointer in sg->page if 
 			 * it is ever allocated.
 			 */
-			sg->address = 0;
+			sg->dma_address = 0;
 			sn_dma_map = (struct sn_dma_maps_s *)sg->page;
 			pciio_dmamap_done((pciio_dmamap_t)sn_dma_map);
 			pciio_dmamap_free((pciio_dmamap_t)sn_dma_map);
@@ -607,19 +599,6 @@
 }
 
 /**
- * sn_dma_address - get the DMA address for the first entry of a scatterlist
- * @sg: sg to look at
- *
- * Gets the DMA address for the scatterlist @sg.  Also known as
- * platform_dma_address() by the IA64 machvec code.
- */
-unsigned long
-sn_dma_address(struct scatterlist *sg)
-{
-	return ((unsigned long)sg->address);
-}
-
-/**
  * sn_dma_supported - test a DMA mask
  * @hwdev: device to test
  * @mask: DMA mask to test
@@ -645,6 +624,5 @@
 EXPORT_SYMBOL(sn_pci_unmap_sg);
 EXPORT_SYMBOL(sn_pci_alloc_consistent);
 EXPORT_SYMBOL(sn_pci_free_consistent);
-EXPORT_SYMBOL(sn_dma_address);
 EXPORT_SYMBOL(sn_pci_dma_supported);
 
diff -urN linux-2.4.21-pre1/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.21-pre2/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
--- linux-2.4.21-pre1/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	Wed Dec 18 14:16:26 2002
@@ -41,7 +41,7 @@
 #ifdef LITTLE_ENDIAN
 #ifdef CONFIG_IA64_SGI_SN1
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
diff -urN linux-2.4.21-pre1/arch/ia64/sn/kernel/setup.c linux-2.4.21-pre2/arch/ia64/sn/kernel/setup.c
--- linux-2.4.21-pre1/arch/ia64/sn/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/arch/ia64/sn/kernel/setup.c	Wed Dec 18 14:16:26 2002
@@ -137,7 +137,7 @@
  * virt_to_page() (asm-ia64/page.h), among other things.
  */
 unsigned long
-sn_map_nr (unsigned long addr)
+sn_map_nr (void *addr)
 {
 	return MAP_NR_DISCONTIG(addr);
 }
diff -urN linux-2.4.21-pre1/arch/ia64/vmlinux.lds.S linux-2.4.21-pre2/arch/ia64/vmlinux.lds.S
--- linux-2.4.21-pre1/arch/ia64/vmlinux.lds.S	Thu Nov 28 15:53:09 2002
+++ linux-2.4.21-pre2/arch/ia64/vmlinux.lds.S	Wed Dec 18 14:16:26 2002
@@ -13,6 +13,8 @@
   /DISCARD/ : {
 	*(.text.exit)
 	*(.data.exit)
+	*(*.text.exit)
+	*(*.data.exit)
 	*(.exitcall.exit)
 	*(.IA_64.unwind.text.exit)
 	*(.IA_64.unwind_info.text.exit)
diff -urN linux-2.4.21-pre1/arch/ppc/kernel/setup.c linux-2.4.21-pre2/arch/ppc/kernel/setup.c
--- linux-2.4.21-pre1/arch/ppc/kernel/setup.c	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre2/arch/ppc/kernel/setup.c	Wed Dec 18 14:16:26 2002
@@ -671,14 +671,16 @@
 	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
 	id->csf_default    = __le16_to_cpu(id->csf_default);
 	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
+	id->mprc           = __le16_to_cpu(id->mprc);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
 	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
 	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
 	for (i = 0; i < 22; i++)
 		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
diff -urN linux-2.4.21-pre1/arch/ppc/mm/tlb.c linux-2.4.21-pre2/arch/ppc/mm/tlb.c
--- linux-2.4.21-pre1/arch/ppc/mm/tlb.c	Tue Aug 28 06:58:33 2001
+++ linux-2.4.21-pre2/arch/ppc/mm/tlb.c	Wed Dec 18 14:16:26 2002
@@ -4,7 +4,7 @@
 /*
  * This file contains the routines for TLB flushing.
  * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the the
+ * physical translations, these routines flush entries from the 
  * hash table also.
  *  -- paulus
  * 
diff -urN linux-2.4.21-pre1/arch/sh/config.in linux-2.4.21-pre2/arch/sh/config.in
--- linux-2.4.21-pre1/arch/sh/config.in	Thu Nov 28 15:53:11 2002
+++ linux-2.4.21-pre2/arch/sh/config.in	Wed Dec 18 14:16:26 2002
@@ -189,7 +189,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT
 fi
 
 source drivers/pci/Config.in
diff -urN linux-2.4.21-pre1/arch/sh/kernel/irq_intc2.c linux-2.4.21-pre2/arch/sh/kernel/irq_intc2.c
--- linux-2.4.21-pre1/arch/sh/kernel/irq_intc2.c	Sat Sep  8 12:29:09 2001
+++ linux-2.4.21-pre2/arch/sh/kernel/irq_intc2.c	Wed Dec 18 14:16:26 2002
@@ -107,7 +107,7 @@
 	}
 
 	disable_irq_nosync(irq);
-	/* Fill the the data we need */
+	/* Fill the data we need */
 	intc2_data[offset].addr=addr;
 	intc2_data[offset].mask=1<<pos;
 		
diff -urN linux-2.4.21-pre1/drivers/block/cciss.c linux-2.4.21-pre2/drivers/block/cciss.c
--- linux-2.4.21-pre1/drivers/block/cciss.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/block/cciss.c	Wed Dec 18 14:16:27 2002
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SMART2 Controllers
- *    Copyright 2000 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
+ *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. 
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 
@@ -44,12 +44,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.42)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,42)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.42");
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -83,7 +84,7 @@
  *  access = Address of the struct of function pointers 
  */
 static struct board_type products[] = {
-	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
+	{ 0x40700E11, "Smart Array 5300", &SA5_access},
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
 	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
@@ -95,6 +96,9 @@
 /* How long to wait (in millesconds) for board to go into simple mode */
 #define MAX_CONFIG_WAIT 1000 
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD 	 128
 #define NR_CMDS		 128 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -113,6 +117,9 @@
 
 static int revalidate_logvol(kdev_t dev, int maxusage);
 static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(int cltr, int opened_vol, __u64 requested_lun);
+static int cciss_rescan_disk(int cltr, int logvol);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -139,6 +146,11 @@
 
 #include "cciss_scsi.c"		/* For SCSI tape support */
 
+#define ENG_GIG	1048576000
+#define ENG_GIG_FACTOR (ENG_GIG/512)
+#define	RAID_UNKNOWN 6
+static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG",
+				   "UNKNOWN"};
 /*
  * Report information about this controller.
  */
@@ -146,53 +158,67 @@
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
 		int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
-
-        ctlr = h->ctlr;
-        size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-                "       Board ID: 0x%08lx\n"
-		"       Firmware Version: %c%c%c%c\n"
-                "       Memory Address: 0x%08lx\n"
-                "       IRQ: %d\n"
-                "       Logical drives: %d\n"
-                "       Current Q depth: %d\n"
-		"       Current # commands on controller %d\n"
-                "       Max Q depth since init: %d\n"
-		"       Max # commands on controller since init: %d\n"
-		"       Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned long)h->vaddr,
-                (unsigned int)h->intr,
-                h->num_luns, 
-                h->Qdepth, h->commands_outstanding,
-		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t*)data;
+	drive_info_struct *drv;
+	unsigned long flags;
+	unsigned int vol_sz, vol_sz_frac;
 
-        pos += size; len += size;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+		
+	ctlr = h->ctlr;
+	size = sprintf(buffer, "%s: HP %s Controller\n"
+ 		"Board ID: 0x%08lx\n"
+		"Firmware Version: %c%c%c%c\n"
+ 		"IRQ: %d\n"
+ 		"Logical drives: %d\n"
+ 		"Current Q depth: %d\n"
+ 		"Current # commands on controller: %d\n"
+ 		"Max Q depth since init: %d\n"
+		"Max # commands on controller since init: %d\n"
+		"Max SG entries since init: %d\n\n",
+  		h->devname,
+  		h->product_name,
+  		(unsigned long)h->board_id,
+  		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
+  		(unsigned int)h->intr,
+  		h->num_luns, 
+  		h->Qdepth, h->commands_outstanding,
+  		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+  
+	pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<h->num_luns; i++) {
-                drv = &h->drv[i];
-                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
-                                ctlr, i, drv->block_size, drv->nr_blocks);
-                pos += size; len += size;
-        }
-
-	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
-                        h->nr_allocs, h->nr_frees);
-        pos += size; len += size;
-
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
-        return len;
+	for(i=0; i<=h->highest_lun; i++) {
+		drv = &h->drv[i];
+		if (drv->nr_blocks == 0)
+			continue;
+		vol_sz = drv->nr_blocks/ENG_GIG_FACTOR; 
+		vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR;
+
+		if (drv->raid_level > 5)
+			drv->raid_level = RAID_UNKNOWN;
+		size = sprintf(buffer+len, "cciss/c%dd%d:"
+				"\t%4d.%02dGB\tRAID %s\n",
+		       		 ctlr, i, vol_sz,vol_sz_frac,
+				 raid_label[drv->raid_level]);
+		pos += size, len += size;
+        }
+
+	*eof = 1;
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	h->busy_configuring = 0;
+	return len;
 }
 
 static int
@@ -206,16 +232,19 @@
 	int rc;
 #endif
 
-	if (count > sizeof(cmd)-1) return -EINVAL;
-	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	if (count > sizeof(cmd)-1) 
+		return -EINVAL;
+	if (copy_from_user(cmd, buffer, count)) 
+		return -EFAULT;
 	cmd[count] = '\0';
-	len = strlen(cmd);	// safe???
+	len = strlen(cmd);	
 	if (cmd[len-1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
 			rc = cciss_engage_scsi(h->ctlr);
-			if (rc != 0) return -rc;
+			if (rc != 0) 
+				return -rc;
 			return count;
 		}
 		/* might be nice to have "disengage" too, but it's not
@@ -234,8 +263,10 @@
 
 	if (proc_cciss == NULL) {
 		proc_cciss = proc_mkdir("cciss", proc_root_driver);
-		if (!proc_cciss)
+		if (!proc_cciss) {
+			printk("cciss:  proc_mkdir failed\n");
 			return;
+		}
 	}
 
 	pde = create_proc_read_entry(hba[i]->devname,
@@ -259,11 +290,10 @@
 	u64bit temp64;
 	dma_addr_t cmd_dma_handle, err_dma_handle;
 
-	if (!get_from_pool)
-	{
+	if (!get_from_pool) {
 		c = (CommandList_struct *) pci_alloc_consistent(
 			h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-        	if(c==NULL)
+        	if (c==NULL)
                  	return NULL;
 		memset(c, 0, sizeof(CommandList_struct));
 
@@ -319,8 +349,7 @@
 	int i;
 	u64bit temp64;
 
-	if( !got_from_pool)
-	{ 
+	if (!got_from_pool) { 
 		temp64.val32.lower = c->ErrDesc.Addr.lower;
 		temp64.val32.upper = c->ErrDesc.Addr.upper;
 		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
@@ -345,24 +374,22 @@
 	
 	/* Loop through each real device */ 
 	hba[ctlr]->gendisk.nr_real = 0; 
-	for(i=0; i< NWD; i++)
-	{
+	for(i=0; i< NWD; i++) {
 		drv = &(hba[ctlr]->drv[i]);
-		if( !(drv->nr_blocks))
+		if (!(drv->nr_blocks))
 			continue;
 		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
 		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
 
 		/* for each partition */ 
-		for(j=0; j<MAX_PART; j++)
-		{
+		for(j=0; j<MAX_PART; j++) {
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
 			hba[ctlr]->hardsizes[ (i<<NWD_SHIFT) + j] = 
 				drv->block_size;
 		}
-		hba[ctlr]->gendisk.nr_real++;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -380,13 +407,23 @@
 		return -ENXIO;
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
-	 * so array config can still work. I don't think I really like this,
+	 * so array config can still work. Root is also allowed to open any
+	 * volume that has a LUN ID, so it can issue IOCTL to reread the
+	 * disk information.  I don't think I really like this.
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
 	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) { /* not online? */
-		if (MINOR(inode->i_rdev) != 0)	 /* not node 0? */
-			return -ENXIO;
+		if (MINOR(inode->i_rdev) != 0) {	 /* not node 0? */
+			/* if not node 0 make sure it is a partition = 0 */
+			if (MINOR(inode->i_rdev) & 0x0f) {
+				return -ENXIO;
+				/* if it is, make sure we have a LUN ID */
+			} else if (hba[ctlr]->drv[MINOR(inode->i_rdev)
+					>> NWD_SHIFT].LunID == 0) {
+				return -ENXIO;
+			}
+		}
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 	}
@@ -428,8 +465,8 @@
 #endif /* CCISS_DEBUG */ 
 	
 	switch(cmd) {
-	case HDIO_GETGEO:
-	{
+	   case HDIO_GETGEO:
+	   {
 		struct hd_geometry driver_geo;
 		if (hba[ctlr]->drv[dsk].cylinders) {
 			driver_geo.heads = hba[ctlr]->drv[dsk].heads;
@@ -446,8 +483,8 @@
 		if (copy_to_user((void *) arg, &driver_geo,
 				sizeof( struct hd_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
+		return 0;
+	   }
 	case HDIO_GETGEO_BIG:
 	{
 		struct hd_big_geometry driver_geo;
@@ -466,7 +503,7 @@
 		if (copy_to_user((void *) arg, &driver_geo,  
 				sizeof( struct hd_big_geometry)))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}
 	case BLKGETSIZE:
 		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
@@ -475,7 +512,7 @@
 		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
 		return 0;
 	case BLKRRPART:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		return revalidate_logvol(inode->i_rdev, 1);
 	case BLKFLSBUF:
@@ -488,30 +525,32 @@
 	case BLKPG:
 	case BLKELVGET:
 	case BLKELVSET:
-		return( blk_ioctl(inode->i_rdev, cmd, arg));
+		return blk_ioctl(inode->i_rdev, cmd, arg);
 	case CCISS_GETPCIINFO:
 	{
 		cciss_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pdev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pdev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
 		if (copy_to_user((void *) arg, &pciinfo,  sizeof( cciss_pci_info_struct )))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}	
 	case CCISS_GETINTINFO:
 	{
 		cciss_coalint_struct intinfo;
 		ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
 		intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
 		if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct )))
 			return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETINTINFO:
         {
@@ -520,25 +559,21 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;	
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;	
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
 			return -EFAULT;
-		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
-		{
-//			printk("cciss_ioctl: delay and count cannot be 0\n");
-			return( -EINVAL);
+		if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) {
+			return -EINVAL;
 		}
+
 		spin_lock_irqsave(&io_request_lock, flags);
 		/* Can only safely update if no commands outstanding */ 
-		if (c->commands_outstanding > 0 )
-		{
-//			printk("cciss_ioctl: cannot change coalasing "
-//				"%d commands outstanding on controller\n", 
-//					c->commands_outstanding);
+		if (c->commands_outstanding > 0 ) {
 			spin_unlock_irqrestore(&io_request_lock, flags);
-			return(-EINVAL);
+			return -EINVAL;
 		}
 		/* Update the field, and then ring the doorbell */ 
 		writel( intinfo.delay, 
@@ -547,8 +582,7 @@
                         &(c->cfgtable->HostWrite.CoalIntCount));
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -557,8 +591,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 	case CCISS_GETNODENAME:
         {
@@ -566,12 +600,13 @@
                 ctlr_info_t *c = hba[ctlr];
 		int i; 
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		for(i=0;i<16;i++)
 			NodeName[i] = readb(&c->cfgtable->ServerName[i]);
                 if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type)))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETNODENAME:
 	{
@@ -580,8 +615,10 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		
 		if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
 			return -EFAULT;
@@ -594,8 +631,7 @@
 			
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -604,8 +640,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 
 	case CCISS_GETHEARTBEAT:
@@ -613,45 +649,68 @@
                 Heartbeat_type heartbeat;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 heartbeat = readl(&c->cfgtable->HeartBeat);
                 if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETBUSTYPES:
         {
                 BusTypes_type BusTypes;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 BusTypes = readl(&c->cfgtable->BusTypes);
                 if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) ))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETFIRMVER:
         {
 		FirmwareVer_type firmware;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		memcpy(firmware, hba[ctlr]->firm_ver, 4);
 
                 if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
         case CCISS_GETDRIVVER:
         {
 		DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+                if (!arg) 
+			return -EINVAL;
 
                 if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) ))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
+	case CCISS_RESCANDISK:
+	{
+		return cciss_rescan_disk(ctlr, dsk);
+	}
+	case CCISS_DEREGDISK:
+		return deregister_disk(ctlr,dsk);
 
+	case CCISS_REGNEWD:
+		return register_new_disk(ctlr, dsk, 0);
+	case CCISS_REGNEWDISK:
+	{
+		__u64 new_logvol;
+
+		if (!arg) 
+			return -EINVAL;
+		if (copy_from_user(&new_logvol, (void *) arg, 
+			sizeof( __u64)))
+			return -EFAULT;
+		return register_new_disk(ctlr, dsk, new_logvol);
+	}
 	case CCISS_GETLUNINFO:
 	{
 		LogvolInfo_struct luninfo;
@@ -665,14 +724,14 @@
   		start = (dsk << NWD_SHIFT);
 		for(i=1; i <MAX_PART; i++) {
 			int minor = start+i;
-			if(hba[ctlr]->sizes[minor] != 0)
+			if (hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
 		}
 		luninfo.num_parts = num_parts;
 		if (copy_to_user((void *) arg, &luninfo,
 				sizeof( LogvolInfo_struct) ))
 			return -EFAULT;
-		return(0);
+		return 0;
 	}
 	case CCISS_PASSTHRU:
 	{
@@ -684,28 +743,28 @@
 		unsigned long flags;
 		DECLARE_COMPLETION(wait);
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 	
-		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
 
 		if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) ))
 			return -EFAULT;
-		if((iocommand.buf_size < 1) && 
-				(iocommand.Request.Type.Direction != XFER_NONE))
-		{	
+		if ((iocommand.buf_size < 1) && 
+				(iocommand.Request.Type.Direction 
+				 	!= XFER_NONE)) {	
 			return -EINVAL;
 		} 
 		/* Check kmalloc limits */
-		if(iocommand.buf_size > 128000)
+		if (iocommand.buf_size > 128000)
 			return -EINVAL;
-		if(iocommand.buf_size > 0)
-		{
+		if (iocommand.buf_size > 0) {
 			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-			if( buff == NULL) 
-				return -EFAULT;
+			if (buff == NULL) 
+				return -ENOMEM;
 		}
-		if (iocommand.Request.Type.Direction == XFER_WRITE)
-		{
+		if (iocommand.Request.Type.Direction == XFER_WRITE) {
 			/* Copy the data into the buffer we created */ 
 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
 			{
@@ -713,40 +772,37 @@
 				return -EFAULT;
 			}
 		}
-		if ((c = cmd_alloc(h , 0)) == NULL)
-		{
+		if ((c = cmd_alloc(h , 0)) == NULL) {
 			kfree(buff);
 			return -ENOMEM;
 		}
-			// Fill in the command type 
+			/* Fill in the command type */
 		c->cmd_type = CMD_IOCTL_PEND;
-			// Fill in Command Header 
-		c->Header.ReplyQueue = 0;  // unused in simple mode
-		if( iocommand.buf_size > 0) 	// buffer to fill 
-		{
+			/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
 			c->Header.SGList = 1;
 			c->Header.SGTotal= 1;
-		} else	// no buffers to fill  
-		{
+		} else	{  /* no buffers to fill  */
 			c->Header.SGList = 0;
                 	c->Header.SGTotal= 0;
 		}
 		c->Header.LUN = iocommand.LUN_info;
-		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
 		
-		// Fill in Request block 
+		/* Fill in Request block */
 		c->Request = iocommand.Request; 
 	
-		// Fill in the scatter gather information
-		if (iocommand.buf_size > 0 ) 
-		{
+		/* Fill in the scatter gather information */
+		if (iocommand.buf_size > 0 ) {
 			temp64.val = pci_map_single( h->pdev, buff,
                                         iocommand.buf_size, 
                                 PCI_DMA_BIDIRECTIONAL);	
 			c->SG[0].Addr.lower = temp64.val32.lower;
 			c->SG[0].Addr.upper = temp64.val32.upper;
 			c->SG[0].Len = iocommand.buf_size;
-			c->SG[0].Ext = 0;  // we are not chaining
+			c->SG[0].Ext = 0;  /* we are not chaining */
 		}
 		c->waiting = &wait;
 
@@ -767,18 +823,17 @@
 
 		/* Copy the error information out */ 
 		iocommand.error_info = *(c->err_info);
-		if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
-		{
+		if (copy_to_user((void *) arg, &iocommand, 
+				sizeof( IOCTL_Command_struct) ) ) {
 			kfree(buff);
 			cmd_free(h, c, 0);
-			return( -EFAULT);	
+			return( -EFAULT);
 		} 	
 
-		if (iocommand.Request.Type.Direction == XFER_READ)
-                {
+		if (iocommand.Request.Type.Direction == XFER_READ) {
                         /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
-			{
+                        if (copy_to_user(iocommand.buf, buff, 
+						iocommand.buf_size)) {
                         	kfree(buff);
 				cmd_free(h, c, 0);
 				return -EFAULT;
@@ -786,9 +841,149 @@
                 }
                 kfree(buff);
 		cmd_free(h, c, 0);
-                return(0);
+                return 0;
 	} 
+	case CCISS_BIG_PASSTHRU:
+	{
+		BIG_IOCTL_Command_struct iocommand;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		char 	*buff[MAXSGENTRIES] = {NULL,};
+		int	buff_size[MAXSGENTRIES] = {0,};
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
+
+		if (!arg) 
+			return -EINVAL;
+		
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+
+		if (copy_from_user(&iocommand, (void *) arg, sizeof( BIG_IOCTL_Command_struct) ))
+			return -EFAULT;
+		if ((iocommand.buf_size < 1) && 
+			(iocommand.Request.Type.Direction != XFER_NONE)) {
+			return -EINVAL;
+		} 
+		/* Check kmalloc limits  using all SGs */
+		if (iocommand.malloc_size > MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (iocommand.buf_size > iocommand.malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		if (iocommand.buf_size > 0) {
+			__u32   size_left_alloc = iocommand.buf_size;
+			BYTE    *data_ptr = (BYTE *) iocommand.buf;
+			while (size_left_alloc > 0) {
+				buff_size[sg_used] = (size_left_alloc 
+							> iocommand.malloc_size)
+					? iocommand.malloc_size : size_left_alloc;
+				buff[sg_used] = kmalloc( buff_size[sg_used], 
+						GFP_KERNEL);
+				if (buff[sg_used] == NULL) {
+					status = -ENOMEM;
+					goto cleanup1;
+				}
+				if (iocommand.Request.Type.Direction == 
+						XFER_WRITE)
+				   /* Copy the data into the buffer created */
+				   if (copy_from_user(buff[sg_used], data_ptr, 
+						buff_size[sg_used])) {
+					status = -ENOMEM;
+					goto cleanup1;			
+				   }
+				size_left_alloc -= buff_size[sg_used];
+				data_ptr += buff_size[sg_used];
+				sg_used++;
+			}
+			
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		/* Fill in the command type */
+		c->cmd_type = CMD_IOCTL_PEND;
+		/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
+			c->Header.SGList = sg_used;
+			c->Header.SGTotal= sg_used;
+		} else	{	/* no buffers to fill */
+			c->Header.SGList = 0;
+			c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = iocommand.LUN_info;
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
+		
+	/* Fill in Request block */
+	c->Request = iocommand.Request; 
+	/* Fill in the scatter gather information */
+	if (iocommand.buf_size > 0 ) {
+		int i;
+		for(i=0; i< sg_used; i++) {
+			temp64.val = pci_map_single( h->pdev, buff[i], 
+					buff_size[i], 
+					PCI_DMA_BIDIRECTIONAL);
+
+			c->SG[i].Addr.lower = temp64.val32.lower;
+			c->SG[i].Addr.upper = temp64.val32.upper;
+			c->SG[i].Len = buff_size[i];
+			c->SG[i].Ext = 0;  /* we are not chaining */
+		}
+	}
+	c->waiting = &wait;
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+	/* unlock the buffers from DMA */
+	for(i=0; i< sg_used; i++) {
+		temp64.val32.lower = c->SG[i].Addr.lower;
+		temp64.val32.upper = c->SG[i].Addr.upper;
+		pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+	}
+	/* Copy the error information out */
+		iocommand.error_info = *(c->err_info);
+		if (copy_to_user((void *) arg, &iocommand, 
+					sizeof( IOCTL_Command_struct) ) ) {
+				cmd_free(h, c, 0);
+				status = -EFAULT;
+				goto cleanup1;
+		}
+		if (iocommand.Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) iocommand.buf;
+	        	for(i=0; i< sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+		
 
+cleanup1:
+		for(i=0; i< sg_used; i++) {
+			if (buff[i] != NULL)
+				kfree(buff[i]);
+		}
+		return status;
+	}
 	default:
 		return -EBADRQC;
 	}
@@ -846,6 +1041,642 @@
 #endif /* CCISS_DEBUG */ 
 	return revalidate_logvol(dev, 0);
 }
+static int deregister_disk(int ctlr, int logvol)
+{
+	unsigned long flags;
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	/* make sure logical volume is NOT is use */
+	if (h->drv[logvol].usage_count > 1 || h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* invalidate the devices and deregister the disk */
+	max_p = gdev->max_p;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		/* printk("invalidating( %d %d)\n", ctlr, minor); */
+		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
+		/* so open will now fail */
+		h->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+	/* check to see if it was the last disk */
+	if (logvol == h->highest_lun) {
+		/* if so, find the new hightest lun */
+		int i, newhighest =-1;
+		for(i=0; i<h->highest_lun; i++) {
+			/* if the disk has size > 0, it is available */
+			if (h->sizes[i << gdev->minor_shift] != 0)
+				newhighest = i;
+		}
+		h->highest_lun = newhighest;
+
+	}
+	--h->num_luns;
+	gdev->nr_real = h->highest_lun+1;
+	/* zero out the disk size info */
+	h->drv[logvol].nr_blocks = 0;
+	h->drv[logvol].block_size = 0;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].LunID = 0;
+	h->busy_configuring = 0;
+	return 0;
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status = IO_OK;
+	DECLARE_COMPLETION(wait);
+
+	if ((c = cmd_alloc(h , 0)) == NULL)
+		return -ENOMEM;
+	c->cmd_type = CMD_IOCTL_PEND;
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else {
+		/* no buffers to fill */
+		c->Header.SGList = 0;
+		c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  /* tag is phys addr of cmd */
+	/* Fill in Request block */
+	switch (cmd) {
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write.
+				Otherwise
+				mode = 1  target = LUNID
+			*/
+			if (use_unit_num != 0) {
+				c->Header.LUN.LogDev.VolId =
+					hba[ctlr]->drv[log_unit].LunID;
+				c->Header.LUN.LogDev.Mode = 1;
+			}
+			if (page_code != 0) {
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;
+		break;
+		case CISS_REPORT_LOG:
+			/* Talking to controller so It's a physical command
+				mode = 00 target = 0.
+				So we have nothing to write.
+			*/
+			c->Request.CDBLen = 12;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CISS_REPORT_LOG;
+			c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
+			c->Request.CDB[7] = (size >> 16) & 0xFF;
+			c->Request.CDB[8] = (size >> 8) & 0xFF;
+			c->Request.CDB[9] = size & 0xFF;
+		break;
+		case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId=
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%x sent attempted\n",				cmd);
+			cmd_free(h, c, 1);
+			return IO_ERROR;
+	};
+
+	/* Fill in the scatter gather information */
+	if (size > 0) {
+		buff_dma_handle.val = (__u64) pci_map_single( h->pdev,
+			buff, size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  /* we are not chaining */
+	}
+
+resend_cmd2:
+	c->waiting = &wait;
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);
+
+
+	if (c->err_info->CommandStatus != 0) {
+		/* an error has occurred */
+		switch (c->err_info->CommandStatus) {
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", c);
+				if (c->err_info->ScsiStatus) {
+					printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n", c,
+						c->err_info->ScsiStatus);
+				}
+			break;
+			case CMD_DATA_UNDERRUN:
+			case CMD_DATA_OVERRUN:
+			/* expected for inquire and report lun commands */
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: cmd %p is "
+					"reported invalid\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_PROTOCOL_ERR:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_HARDWARE_ERR:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					" hardware error\n", c);
+				return_status = IO_ERROR;
+				break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", c);
+				if (c->retry_count < MAX_CMD_RETRIES) 
+				{ 
+					printk(KERN_WARNING "retrying cmd\n"); 
+					c->retry_count++; 
+					/* erase the old error */ 
+					/* information */ 
+					memset(c->err_info, 0, 
+						sizeof(ErrorInfo_struct)); 
+					return_status = IO_OK;
+					INIT_COMPLETION(wait);
+					goto resend_cmd2;
+					
+				}
+				return_status = IO_ERROR;
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", c,
+						c->err_info->CommandStatus);
+				return_status = IO_ERROR;
+		}
+	}
+
+	/* unlock the buffers from DMA */
+	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+			size, PCI_DMA_BIDIRECTIONAL);
+	cmd_free(h, c, 0);
+	return return_status;
+}
+static int register_new_disk(int ctlr, int opened_vol, __u64 requested_lun)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+	int num_luns;
+	int logvol;
+	int new_lun_found = 0;
+	int new_lun_index = 0;
+	int free_index_found = 0;
+	int free_index = 0;
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int listlength = 0;
+	__u32 lunid = 0;
+	unsigned int block_size;
+	unsigned int total_size;
+	unsigned long flags;
+	int req_lunid = (int) (requested_lun & (__u64) 0xffffffff);
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->num_luns >= CISS_MAX_LUN) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EINVAL;
+	}
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		kfree(size_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+
+	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if (return_code == IO_OK) {
+		/* printk("LUN Data\n--------------------------\n"); */
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[2])) << 8;
+		listlength |= 0xff &
+			(unsigned int)(ld_buff->LUNListLength[3]);
+	} else {
+		/* reading number of logical volumes failed */
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+		h->busy_configuring = 0;
+		return -1;
+	}
+	num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (num_luns > CISS_MAX_LUN)
+		num_luns = CISS_MAX_LUN;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  num_luns);
+#endif
+	for(i=0; i<  num_luns; i++) {
+		int j;
+		int lunID_found = 0;
+
+		lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+		lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+		/* check to see if this is a new lun */
+		for(j=0; j <= h->highest_lun; j++) {
+#ifdef CCISS_DEBUG
+			printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+						lunid);
+#endif /* CCISS_DEBUG */
+			if (h->drv[j].LunID == lunid) {
+				lunID_found = 1;
+				break;
+			}
+
+		}
+		if (lunID_found == 1)
+			continue;
+		else {	/* new lun found */
+			
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			if (req_lunid)  /* we are looking for a specific lun */
+			{
+				if (lunid != req_lunid)
+				{
+#ifdef CCISS_DEBUG
+					printk("new lun %x is not %x\n",
+							lunid, req_lunid);
+#endif /* CCISS_DEBUG */
+					continue;
+				}
+			}
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;
+		}
+	}
+	if (!new_lun_found) {
+		printk(KERN_DEBUG "cciss:  New Logical Volume not found\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+	/* Now find the free index 	*/
+	for(i=0; i <CISS_MAX_LUN; i++) {
+#ifdef CCISS_DEBUG
+		printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+		if (hba[ctlr]->drv[i].LunID == 0) {
+#ifdef CCISS_DEBUG
+			printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			free_index_found = 1;
+			free_index = i;
+			break;
+		}
+	}
+	if (!free_index_found) {
+		printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+
+	logvol = free_index;
+	hba[ctlr]->drv[logvol].LunID = lunid;
+		/* there could be gaps in lun numbers, track hightest */
+	if (hba[ctlr]->highest_lun < logvol)
+		hba[ctlr]->highest_lun = logvol;
+
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr,
+			size_buff, sizeof(ReadCapdata_struct), 1,
+			logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int) size_buff->total_size[0]) << 24;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[1]) << 16;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[2]) << 8;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[3]);
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+			(unsigned int) size_buff->block_size[0]) << 24;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[1]) << 16;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[2]) << 8;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[3]);
+	} else {
+		/* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = 0;
+		block_size = BLOCK_SIZE;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+		sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING
+			"cciss: reading geometry failed, "
+			"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* secs/trk */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+			hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+		} else {
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+			hba[ctlr]->drv[logvol].raid_level = 
+				inq_buff->data_byte[8];
+		}
+	} else {
+		/* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+			"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].block_size = block_size;
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors per track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+	}
+	if (hba[ctlr]->drv[logvol].raid_level > 5)
+		hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders, 
+		raid_label[hba[ctlr]->drv[logvol].raid_level]);
+
+	/* special case for c?d0, which may be opened even when
+	   it does not "exist".  In that case, don't mess with usage count.
+	   Also, /dev/c1d1 could be used to re-add c0d0 so we can't just 
+	   check whether logvol == 0, must check logvol != opened_vol */
+	if (logvol != opened_vol)
+		hba[ctlr]->drv[logvol].usage_count = 0;
+
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = total_size;
+	hba[ctlr]->sizes[start] = total_size;
+
+	for(i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = block_size;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks);
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	h->busy_configuring = 0;
+	return logvol;
+}
+
+static int cciss_rescan_disk(int ctlr, int logvol)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	int start, max_p, i;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	unsigned int block_size;
+	unsigned int total_size;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	if (hba[ctlr]->sizes[logvol << NWD_SHIFT] != 0) {
+		/* disk is possible on line, return just a warning */
+		return 1;
+	}
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(size_buff);
+		return -1;
+	}
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+				sizeof( ReadCapdata_struct), 1, logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int)(size_buff->total_size[0])) << 24;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[1])) << 16;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[2])) << 8;
+		total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3]));
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+				(unsigned int)(size_buff->block_size[0])) << 24;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[1])) << 16;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[2])) << 8;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[3]));
+	} else { /* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = block_size = 0;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+			sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING "cciss: reading geometry failed, "
+				"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* Sectors/track */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+		} else {
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+		}
+	} else { /* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+				"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors / track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+	}
+
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d \n\n", 
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders);
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = hba[ctlr]->sizes[start]= total_size;
+
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks );
+
+	kfree(size_buff);
+	kfree(inq_buff);
+	return 0;
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -853,20 +1684,21 @@
  */
 static unsigned long pollcomplete(int ctlr)
 {
-        unsigned long done;
-        int i;
+	unsigned long done;
+	int i;
 
-        /* Wait (up to 2 seconds) for a command to complete */
+	/* Wait (up to 20 seconds) for a command to complete */
 
-        for (i = 200000; i > 0; i--) {
-                done = hba[ctlr]->access.command_completed(hba[ctlr]);
-                if (done == FIFO_EMPTY) {
-                        udelay(10);     /* a short fixed delay */
-                } else
-                        return (done);
-        }
-        /* Invalid address to tell caller we ran out of time */
-        return 1;
+        for (i = 20 * HZ; i > 0; i--) {
+		done = hba[ctlr]->access.command_completed(hba[ctlr]);
+		if (done == FIFO_EMPTY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} else
+			return done;
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
 }
 /*
  * Send a command to the controller, and wait for it to complete.  
@@ -889,28 +1721,26 @@
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
+	int status = IO_OK;
 
 	c = cmd_alloc(info_p, 1);
-	if (c == NULL)
-	{
+	if (c == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
-		return(IO_ERROR);
+		return IO_ERROR;
 	}
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
 		c->Header.SGList = 1;
 		c->Header.SGTotal= 1;
-	} else	// no buffers to fill  
-	{
+	} else	{	/* no buffers to fill  */
 		c->Header.SGList = 0;
                 c->Header.SGTotal= 0;
 	}
-	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-	// Fill in Request block 	
-	switch(cmd)
-	{
+	c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+					   /* the cmd block for tag */
+	/* Fill in Request block */
+	switch (cmd) {
 		case  CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
 				to controller so It's a physical command
@@ -921,29 +1751,27 @@
 				otherwise, if use_unit_num == 2,
 				mode = 0(periph dev addr) target = scsi3addr
 			*/
-			if(use_unit_num == 1)
-			{
+			if (use_unit_num == 1) {
 				c->Header.LUN.LogDev.VolId=
                                 	hba[ctlr]->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
 			}
-			else if (use_unit_num == 2)
-			{
+			else if (use_unit_num == 2) {
 				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
-				c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+				c->Header.LUN.LogDev.Mode = 0; 
+							/* phys dev addr */
 			}
 
 			/* are we trying to read a vital product page */
-			if(page_code != 0)
-			{
+			if (page_code != 0) {
 				c->Request.CDB[1] = 0x01;
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;  
-			c->Request.Type.Direction = XFER_READ; // Read 
-			c->Request.Timeout = 0; // Don't time out 
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] =  CISS_INQUIRY;
 			c->Request.CDB[4] = size  & 0xFF;  
 		break;
@@ -954,12 +1782,12 @@
                                 So we have nothing to write.
                         */
                         c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] = cmd;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
                         c->Request.CDB[7] = (size >> 16) & 0xFF;
                         c->Request.CDB[8] = (size >> 8) & 0xFF;
                         c->Request.CDB[9] = size & 0xFF;
@@ -970,38 +1798,38 @@
 				hba[ctlr]->drv[log_unit].LunID;
 			c->Header.LUN.LogDev.Mode = 1;
 			c->Request.CDBLen = 10;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
                         c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
 		case CCISS_CACHE_FLUSH:
 			c->Request.CDBLen = 12;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command.
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;
-			c->Request.Type.Direction = XFER_WRITE; // No data
-			c->Request.Timeout = 0; // Don't time out
-			c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
+			c->Request.Type.Direction = XFER_WRITE; /* No data */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = BMIC_WRITE;  /* BMIC Passthru */
 			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
 		break;
 		default:
 			printk(KERN_WARNING
-				"cciss:  Unknown Command 0x%c sent attempted\n",
+				"cciss:  Unknown Command 0x%x sent attempted\n",
 				  cmd);
 			cmd_free(info_p, c, 1);
-			return(IO_ERROR);
+			return IO_ERROR;
 	};
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
+	/* Fill in the scatter gather information */
+	if (size > 0) {
 		buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, 
 			buff, size, PCI_DMA_BIDIRECTIONAL);
 		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
 		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
 		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  // we are not chaining
+		c->SG[0].Ext = 0;  /* we are not chaining */
 	}
+resend_cmd1:
 	/*
          * Disable interrupt
          */
@@ -1012,11 +1840,9 @@
 	
 	/* Make sure there is room in the command FIFO */
         /* Actually it should be completely empty at this time. */
-        for (i = 200000; i > 0; i--) 
-	{
+        for (i = 200000; i > 0; i--) {
 		/* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-		{
+                if (!(info_p->access.fifo_full(info_p))) {
 			
                         break;
                 }
@@ -1034,13 +1860,9 @@
 	printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	/* unlock the data buffer from DMA */
-	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
 	if (complete != 1) {
 		if ( (complete & CISS_ERROR_BIT)
-		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-		     {
+		     && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
 			/* if data overrun or underun on Report command 
 				ignore it 
 			*/
@@ -1051,41 +1873,64 @@
 					CMD_DATA_OVERRUN) || 
 				 (c->err_info->CommandStatus == 
 					CMD_DATA_UNDERRUN)
-			 	))
-			{
+			 	)) {
 				complete = c->busaddr;
-			} else
-			{
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+			} else {
+				if (c->err_info->CommandStatus == 
+						CMD_UNSOLICITED_ABORT) {
+					printk(KERN_WARNING "cciss: "
+						"cmd %p aborted do "
+					"to an unsolicited abort \n", c); 
+					if (c->retry_count < MAX_CMD_RETRIES) {
+						printk(KERN_WARNING
+						   "retrying cmd\n");
+						c->retry_count++;
+						/* erase the old error */
+						/* information */
+						memset(c->err_info, 0, 
+						   sizeof(ErrorInfo_struct));
+						goto resend_cmd1;
+					} else {
+						printk(KERN_WARNING
+						   "retried to many times\n");
+						status = IO_ERROR;
+						goto cleanup1;
+					}
+				}
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" Error %x \n", ctlr, 
 					c->err_info->CommandStatus); 
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" offensive info\n"
 				"  size %x\n   num %x   value %x\n", ctlr,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-				cmd_free(info_p,c, 1);
-				return(IO_ERROR);
+				status = IO_ERROR;
+				goto cleanup1;
 			}
 		}
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+                        status = IO_ERROR;
+			goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+                status = IO_ERROR;
         }
+		
+cleanup1:	
+	/* unlock the data buffer from DMA */
+	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+                                size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(info_p, c, 1);
-        return (IO_OK);
+        return status;
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1136,11 +1981,9 @@
 {
 	CommandList_struct *c;
 	
-	while(( c = h->reqQ) != NULL )
-	{
+	while(( c = h->reqQ) != NULL ) {
 		/* can't do anything if fifo is full */
-		if ((h->access.fifo_full(h)))
-		{
+		if ((h->access.fifo_full(h))) {
 			printk(KERN_WARNING "cciss: fifo full \n");
 			return;
 		}
@@ -1160,8 +2003,7 @@
 {
 	struct buffer_head *xbh;
 	
-	while(bh)
-	{
+	while(bh) {
 		xbh = bh->b_reqnext; 
 		bh->b_reqnext = NULL; 
 		blk_finished_io(bh->b_size >> 9);
@@ -1169,39 +2011,44 @@
 		bh = xbh;
 	}
 } 
+/* This code assumes io_request_lock is already held */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */ 
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+	/* erase the old error information */
+	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+	/* add it to software queue and then send it to the controller */
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth; 
+
+	start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, 
+		int timeout)
 {
 	int status = 1;
+	int retry_cmd = 0;
 	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
-	/* unmap the DMA mapping for all the scatter gather elements */
-	if (cmd->Request.Type.Direction == XFER_READ)
-		ddir = PCI_DMA_FROMDEVICE;
-	else
-		ddir = PCI_DMA_TODEVICE;
-	for(i=0; i<cmd->Header.SGList; i++)
-	{
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, ddir);
-	}
 
-	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(cmd->err_info->CommandStatus)
-		{
+	if (cmd->err_info->CommandStatus != 0) { 
+		/* an error has occurred */ 
+		switch (cmd->err_info->CommandStatus) {
 			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
 				status = 0;
 			
-				if( cmd->err_info->ScsiStatus == 0x02) {
+				if (cmd->err_info->ScsiStatus == 0x02) {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has CHECK CONDITION,"
 						" sense key = 0x%x\n", cmd,
@@ -1209,10 +2056,9 @@
 					/* check the sense key */
 					sense_key = 0xf & 
 						cmd->err_info->SenseInfo[2];
-					/* no status or recovered error */
-					if ((sense_key == 0x0) ||
-						(sense_key == 0x1))
-							status = 1;
+					/* recovered error */
+					if ( sense_key == 0x1)
+						status = 1;
 				} else {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has SCSI Status 0x%x\n",
@@ -1260,8 +2106,18 @@
 				status=0;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", cmd);
+				printk(KERN_WARNING "cciss: cmd %p aborted do "
+					"to an unsolicited abort \n",
+				       	cmd);
+				if (cmd->retry_count < MAX_CMD_RETRIES) {
+					retry_cmd=1;
+					printk(KERN_WARNING
+						"retrying cmd\n");
+					cmd->retry_count++;
+				} else {
+					printk(KERN_WARNING
+					"retried to many times\n");
+				}
 				status=0;
 			break;
 			case CMD_TIMEOUT:
@@ -1276,12 +2132,29 @@
 				status=0;
 		}
 	}
+	/* We need to return this command */
+	if (retry_cmd) {
+		resend_cciss_cmd(h,cmd);
+		return;
+	}	
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
+	}
 	complete_buffers(cmd->rq->bh, status);
-
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", cmd->rq);
 #endif /* CCISS_DEBUG */ 
 	end_that_request_last(cmd->rq);
+	cmd_free(h,cmd,1);
 }
 
 
@@ -1298,7 +2171,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-	if (blk_seg_merge_ok(rq->bhtail, bh))
+	if (blk_seg_merge_ok(rq->bhtail, bh))	
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1356,8 +2229,7 @@
 	if (creq->nr_segments > MAXSGENTRIES)
                 BUG();
 
-        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-        {
+        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
                 printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
                                 h->ctlr, creq->rq_dev, creq);
                 blkdev_dequeue_request(creq);
@@ -1379,34 +2251,33 @@
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	c->Header.Tag.lower = c->busaddr;  /* use the physical address */
+					/* the cmd block for tag */
 	c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
 	c->Header.LUN.LogDev.Mode = 1;
-	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+	c->Request.CDBLen = 10; /* 12 byte commands not in FW yet. */
+	c->Request.Type.Type =  TYPE_CMD; /* It is a command.  */
 	c->Request.Type.Attribute = ATTR_SIMPLE; 
 	c->Request.Type.Direction = 
 		(creq->cmd == READ) ? XFER_READ: XFER_WRITE; 
-	c->Request.Timeout = 0; // Don't time out	
+	c->Request.Timeout = 0; /* Don't time out */
 	c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE;
 	start_blk = hba[h->ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;
 #ifdef CCISS_DEBUG
 	if (bh == NULL)
 		panic("cciss: bh== NULL?");
-	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
+	printk(KERN_DEBUG "cciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
 	seg = 0;
 	lastdataend = ~0ULL;
-	while(bh)
-	{
+	while(bh) {
 		if (bh_phys(bh) == lastdataend)
-		{  // tack it on to the last segment 
+		{  /* tack it on to the last segment */
 			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
-		} else
-		{
+		} else {
 			if (seg == MAXSGENTRIES)
 				BUG();
 			tmp_sg[seg].page = bh->b_page;
@@ -1429,10 +2300,10 @@
 			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+                c->SG[i].Ext = 0;  /* we are not chaining */
 	}
 	/* track how many SG entries we are using */ 
-	if( seg > h->maxSG)
+	if (seg > h->maxSG)
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
@@ -1441,11 +2312,11 @@
 
 	c->Header.SGList = c->Header.SGTotal = seg;
 	c->Request.CDB[1]= 0;
-	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	/* MSB */
 	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
 	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
 	c->Request.CDB[5]= start_blk & 0xff;
-	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
+	c->Request.CDB[6]= 0; /* (sect >> 24) & 0xff; MSB */
 	c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
 	c->Request.CDB[8]= creq->nr_sectors & 0xff; 
 	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -1454,7 +2325,7 @@
 
 	addQ(&(h->reqQ),c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
+	if (h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
 	goto next;
@@ -1472,7 +2343,7 @@
 
 
 	/* Is this interrupt for us? */
-	if ( h->access.intr_pending(h) == 0)
+	if (h->access.intr_pending(h) == 0)
 		return;
 
 	/*
@@ -1480,14 +2351,11 @@
 	 * we had better do something about it.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
-	while( h->access.intr_pending(h))
-	{
-		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
-		{
+	while( h->access.intr_pending(h)) {
+		while((a = h->access.command_completed(h)) != FIFO_EMPTY) {
 			a1 = a;
 			a &= ~3;
-			if ((c = h->cmpQ) == NULL)
-			{  
+			if ((c = h->cmpQ) == NULL) {  
 				printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
 				continue;	
 			} 
@@ -1503,8 +2371,7 @@
 			 if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
-					complete_command(c, 0);
-					cmd_free(h, c, 1);
+					complete_command(h, c, 0);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					complete(c->waiting);
 				}
@@ -1566,7 +2433,7 @@
 static void release_io_mem(ctlr_info_t *c)
 {
 	/* if IO mem was not protected do nothing */
-	if( c->io_mem_addr == 0)
+	if (c->io_mem_addr == 0)
 		return;
 	release_region(c->io_mem_addr, c->io_mem_length);
 	c->io_mem_addr = 0;
@@ -1591,15 +2458,13 @@
 	for(i=0; i<6; i++)
 		addr[i] = pdev->resource[i].start;
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-		return( -1);
+		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) {
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
-		return(-1);
+		return -1;
 	}
 	
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
@@ -1615,7 +2480,7 @@
 	/* check to see if controller has been disabled */
 	if (!(command & 0x02)) {
 		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-		return(-1);
+		return -1;
 	}
 	/* search for our IO range so we can protect it */
 	for (i=0; i<6; i++) {
@@ -1709,8 +2574,7 @@
 	if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
 	      (readb(&c->cfgtable->Signature[1]) != 'I') ||
 	      (readb(&c->cfgtable->Signature[2]) != 'S') ||
-	      (readb(&c->cfgtable->Signature[3]) != 'S') )
-	{
+	      (readb(&c->cfgtable->Signature[3]) != 'S') ) {
 		printk("Does not appear to be a valid CISS config table\n");
 		return -1;
 	}
@@ -1723,8 +2587,7 @@
 		&(c->cfgtable->HostWrite.TransportRequest));
 	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-	for(i=0;i<MAX_CONFIG_WAIT;i++)
-	{
+	for(i=0;i<MAX_CONFIG_WAIT;i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
@@ -1738,8 +2601,7 @@
 	print_cfg_table(c->cfgtable);	
 #endif /* CCISS_DEBUG */ 
 
-	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-	{
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
 		printk(KERN_WARNING "cciss: unable to get board into"
 					" simple mode\n");
 		return -1;
@@ -1764,22 +2626,19 @@
 	int total_size; 
 
 	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-	if (ld_buff == NULL)
-	{
+	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
 	memset(ld_buff, 0, sizeof(ReportLunData_struct));
 	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
+        if (size_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
 		kfree(ld_buff);
                 return;
         }
 	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
+        if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
 		kfree(size_buff);
@@ -1788,14 +2647,12 @@
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
 		sizeof(InquiryData_struct), 0, 0 ,0, NULL);
-	if (return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
 		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
 		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
 		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-	} else /* send command failed */
-	{
+	} else  {	/* send command failed */
 		printk(KERN_WARNING "cciss: unable to determine firmware"
 			" version of controller\n");
 	}
@@ -1803,8 +2660,7 @@
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
 			sizeof(ReportLunData_struct), 0, 0, 0, NULL);
 
-	if( return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
 		printk("LUN Data\n--------------------------\n");
 #endif /* CCISS_DEBUG */ 
@@ -1813,16 +2669,14 @@
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
 		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-	} else /* reading number of logical volumes failed */
-	{
+	} else { /* reading number of logical volumes failed */
 		printk(KERN_WARNING "cciss: report logical volume"
 			" command failed\n");
 		listlength = 0;
 	}
-	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-	{
-		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
+	hba[cntl_num]->num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+		printk(KERN_ERR "cciss:  only %d number of logical volumes supported\n",
 			CISS_MAX_LUN);
 		hba[cntl_num]->num_luns = CISS_MAX_LUN;
 	}
@@ -1831,8 +2685,9 @@
 		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
 		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
 #endif /* CCISS_DEBUG */
-	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
-	{
+
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+	for(i=0; i<  hba[cntl_num]->num_luns; i++) {
 	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
@@ -1848,8 +2703,7 @@
 	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
 				sizeof( ReadCapdata_struct), 1, i, 0, NULL);
-	  	if (return_code == IO_OK)
-		{
+	  	if (return_code == IO_OK) {
 			total_size = (0xff & 
 				(unsigned int)(size_buff->total_size[0])) << 24;
 			total_size |= (0xff & 
@@ -1858,7 +2712,8 @@
 				(unsigned int)(size_buff->total_size[2])) << 8;
 			total_size |= (0xff & (unsigned int)
 				(size_buff->total_size[3])); 
-			total_size++; // command returns highest block address
+			total_size++; 	/* command returns highest */
+					/* block address */
 
 			block_size = (0xff & 
 				(unsigned int)(size_buff->block_size[0])) << 24;
@@ -1868,8 +2723,7 @@
 				(unsigned int)(size_buff->block_size[2])) << 8;
                 	block_size |= (0xff & 
 				(unsigned int)(size_buff->block_size[3]));
-		} else /* read capacity command failed */ 
-		{
+		} else {	/* read capacity command failed */ 
 			printk(KERN_WARNING "cciss: read capacity failed\n");
 			total_size = block_size = 0; 
 		}	
@@ -1880,18 +2734,18 @@
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
 			sizeof(InquiryData_struct), 1, i, 0xC1, NULL );
-	  	if (return_code == IO_OK)
-		{
-			if(inq_buff->data_byte[8] == 0xFF)
-			{
+	  	if (return_code == IO_OK) {
+			if (inq_buff->data_byte[8] == 0xFF) {
 			   printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n");
 
                            hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
                            hba[cntl_num]->drv[i].heads = 255;
-                           hba[cntl_num]->drv[i].sectors = 32; // Sectors per track
-                           hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;                	} else
-			{
+                           hba[cntl_num]->drv[i].sectors = 32; /* Sectors */
+			   					/* per track */
+                           hba[cntl_num]->drv[i].cylinders = total_size 
+				   				/ 255 / 32;
+			} else {
 
 		 	   hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
@@ -1903,23 +2757,27 @@
 					(inq_buff->data_byte[4] & 0xff) << 8;
 			   hba[cntl_num]->drv[i].cylinders += 
                                         inq_buff->data_byte[5];
+                           hba[cntl_num]->drv[i].raid_level = 
+					inq_buff->data_byte[8]; 
 			}
 		}
-		else /* Get geometry failed */
-		{
+		else {	/* Get geometry failed */
 			printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); 
 
 			hba[cntl_num]->drv[i].block_size = block_size;
 			hba[cntl_num]->drv[i].nr_blocks = total_size;
 			hba[cntl_num]->drv[i].heads = 255;
-			hba[cntl_num]->drv[i].sectors = 32; // Sectors per track 
+			hba[cntl_num]->drv[i].sectors = 32; 	/* Sectors */
+								/* per track */
 			hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;
 		}
-		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+		if (hba[cntl_num]->drv[i].raid_level > 5)
+			hba[cntl_num]->drv[i].raid_level = RAID_UNKNOWN;
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
 			hba[cntl_num]->drv[i].heads, 
 			hba[cntl_num]->drv[i].sectors,
-			hba[cntl_num]->drv[i].cylinders);
-
+			hba[cntl_num]->drv[i].cylinders,
+			raid_label[hba[cntl_num]->drv[i].raid_level]); 
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
@@ -1931,22 +2789,19 @@
 static int alloc_cciss_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if (hba[i]==NULL) {
 				printk(KERN_ERR "cciss: out of memory.\n");
-				return (-1);
+				return -1;
 			}
-			return (i);
+			return i;
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
 		" of 8 controllers.\n");
-	return(-1);
+	return -1;
 }
 
 static void free_hba(int i)
@@ -1972,13 +2827,12 @@
 		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
 			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if( i < 0 ) 
-		return (-1);
+	if (i < 0 ) 
+		return -1;
 	memset(hba[i], 0, sizeof(ctlr_info_t));
-	if (cciss_pci_init(hba[i], pdev) != 0)
-	{
+	if (cciss_pci_init(hba[i], pdev) != 0) {
 		free_hba(i);
-		return (-1);
+		return -1;
 	}
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
@@ -1995,26 +2849,25 @@
 		return -ENODEV;
 	}
 		
-	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) {
 		printk(KERN_ERR "cciss:  Unable to get major number "
 			"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-	if( request_irq(hba[i]->intr, do_cciss_intr, 
+	if (request_irq(hba[i]->intr, do_cciss_intr, 
 		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-			hba[i]->devname, hba[i]))
-	{
-		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+			hba[i]->devname, hba[i])) {
+
+		printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
 			hba[i]->intr, hba[i]->devname);
 		unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
         	((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
@@ -2024,17 +2877,17 @@
 	hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
 		hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
 		&(hba[i]->errinfo_pool_dhandle));
-	if((hba[i]->cmd_pool_bits == NULL) 
+	if ((hba[i]->cmd_pool_bits == NULL) 
 		|| (hba[i]->cmd_pool == NULL)
-		|| (hba[i]->errinfo_pool == NULL))
-        {
-		if(hba[i]->cmd_pool_bits)
+		|| (hba[i]->errinfo_pool == NULL)) {
+
+		if (hba[i]->cmd_pool_bits)
                 	kfree(hba[i]->cmd_pool_bits);
-                if(hba[i]->cmd_pool)
+                if (hba[i]->cmd_pool)
                 	pci_free_consistent(hba[i]->pdev,  
 				NR_CMDS * sizeof(CommandList_struct), 
 				hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);	
-		if(hba[i]->errinfo_pool)
+		if (hba[i]->errinfo_pool)
 			pci_free_consistent(hba[i]->pdev,
 				NR_CMDS * sizeof( ErrorInfo_struct),
 				hba[i]->errinfo_pool, 
@@ -2044,7 +2897,7 @@
 		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
-		return(-1);
+		return -1;
 	}
 
 	/* Initialize the pdev driver private data. 
@@ -2091,7 +2944,8 @@
 	hba[i]->gendisk.max_p = MAX_PART;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->num_luns;
+	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;
+	hba[i]->gendisk.fops = &cciss_fops;
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -2105,7 +2959,7 @@
 
 	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
 
-	return(1);
+	return 1;
 }
 
 static void __devexit cciss_remove_one (struct pci_dev *pdev)
@@ -2115,15 +2969,13 @@
 	char flush_buf[4];
 	int return_code; 
 
-	if (pci_get_drvdata(pdev) == NULL)
-	{
+	if (pci_get_drvdata(pdev) == NULL) {
 		printk( KERN_ERR "cciss: Unable to remove device \n");
 		return;
 	}
 	tmp_ptr = pci_get_drvdata(pdev);
 	i = tmp_ptr->ctlr;
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cciss: device appears to "
 			"already be removed \n");
 		return;
@@ -2184,7 +3036,7 @@
 static int __init init_cciss_module(void)
 {
 
-	return ( cciss_init());
+	return cciss_init();
 }
 
 static void __exit cleanup_cciss_module(void)
@@ -2193,10 +3045,8 @@
 
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
-	for (i=0; i< MAX_CTLR; i++) 
-	{
-		if (hba[i] != NULL)
-		{
+	for (i=0; i< MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
 			printk(KERN_WARNING "cciss: had to remove"
 					" controller %d\n", i);
 			cciss_remove_one(hba[i]->pdev);
diff -urN linux-2.4.21-pre1/drivers/block/cciss.h linux-2.4.21-pre2/drivers/block/cciss.h
--- linux-2.4.21-pre1/drivers/block/cciss.h	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/block/cciss.h	Wed Dec 18 14:16:27 2002
@@ -27,13 +27,14 @@
 };
 typedef struct _drive_info_struct
 {
- 	__u32   LunID;	
-	int 	usage_count;
-	int 	nr_blocks;
-	int	block_size;
-	int 	heads;
-	int	sectors;
-	int 	cylinders;
+ 	__u32   	LunID;	
+	int 		usage_count;
+	unsigned int 	nr_blocks;
+	int		block_size;
+	int 		heads;
+	int		sectors;
+	int 		cylinders;
+	int 		raid_level;
 } drive_info_struct;
 
 struct ctlr_info 
@@ -55,6 +56,7 @@
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
 	int	num_luns;
+	int 	highest_lun;
 	int	usage_count;  /* number of opens all all minor devices */
 
 	// information about each logical volume
@@ -85,6 +87,7 @@
 	int              sizes[256];
 	int              blocksizes[256];
 	int              hardsizes[256];
+	int busy_configuring;
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -urN linux-2.4.21-pre1/drivers/block/cciss_cmd.h linux-2.4.21-pre2/drivers/block/cciss_cmd.h
--- linux-2.4.21-pre1/drivers/block/cciss_cmd.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/block/cciss_cmd.h	Wed Dec 18 14:16:27 2002
@@ -1,16 +1,17 @@
 #ifndef CCISS_CMD_H
 #define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+/* ########################################################################## */
+/* DEFINES                                                                    */
+/* ########################################################################## */
 #define CISS_VERSION "1.00"
 
-//general boundary defintions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+/* general boundary defintions */
+#define SENSEINFOBYTES          32	/* note that this value may vary */
+					/* between host implementations  */
 #define MAXSGENTRIES            31
 #define MAXREPLYQS              256
 
-//Command Status value
+/* Command Status value */
 #define CMD_SUCCESS             0x0000
 #define CMD_TARGET_STATUS       0x0001
 #define CMD_DATA_UNDERRUN       0x0002
@@ -25,30 +26,30 @@
 #define CMD_TIMEOUT             0x000B
 #define CMD_UNABORTABLE		0x000C
 
-//transfer direction
+/* transfer direction */
 #define XFER_NONE               0x00
 #define XFER_WRITE              0x01
 #define XFER_READ               0x02
 #define XFER_RSVD               0x03
 
-//task attribute
+/* task attribute */
 #define ATTR_UNTAGGED           0x00
 #define ATTR_SIMPLE             0x04
 #define ATTR_HEADOFQUEUE        0x05
 #define ATTR_ORDERED            0x06
 #define ATTR_ACA                0x07
 
-//cdb type
+/* cdb type */
 #define TYPE_CMD				0x00
 #define TYPE_MSG				0x01
 
-//config space register offsets
+/* config space register offsets */
 #define CFG_VENDORID            0x00
 #define CFG_DEVICEID            0x02
 #define CFG_I2OBAR              0x10
 #define CFG_MEM1BAR             0x14
 
-//i2o space register offsets
+/* i2o space register offsets */
 #define I2O_IBDB_SET            0x20
 #define I2O_IBDB_CLEAR          0x70
 #define I2O_INT_STATUS          0x30
@@ -56,7 +57,7 @@
 #define I2O_IBPOST_Q            0x40
 #define I2O_OBPOST_Q            0x44
 
-//Configuration Table
+/* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 
@@ -78,24 +79,24 @@
    __u64	val;
 } u64bit;
 
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
-#define QWORD vals32 
-
-//###########################################################################
-//STRUCTURES
-//###########################################################################
+/*  Type defs used in the following structs */
+typedef	__u8 BYTE;
+typedef	__u16 WORD;
+typedef __u16 HWORD;
+typedef	__u32 DWORD; 
+typedef vals32 QWORD; 
+
+/* ######################################################################### */
+/* STRUCTURES                                                                */
+/* ######################################################################### */
 #define CISS_MAX_LUN	16	
 #define CISS_MAX_PHYS_LUN	1024
-// SCSI-3 Cmmands 
+/* SCSI-3 Cmmands  */
 
 #pragma pack(1)	
 
 #define CISS_INQUIRY 0x12
-//Date returned
+/* Data returned */
 typedef struct _InquiryData_struct
 {
   BYTE data_byte[36];
@@ -103,7 +104,7 @@
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
 #define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
-// Data returned
+/*  Data returned */
 typedef struct _ReportLUNdata_struct
 {
   BYTE LUNListLength[4];
@@ -114,39 +115,39 @@
 #define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
 typedef struct _ReadCapdata_struct
 {
-  BYTE total_size[4];	// Total size in blocks
-  BYTE block_size[4];	// Size of blocks in bytes
+  BYTE total_size[4];	/* Total size in blocks */
+  BYTE block_size[4];	/* Size of blocks in bytes */
 } ReadCapdata_struct;
 
-// 12 byte commands not implemented in firmware yet. 
-// #define CCISS_READ 	0xa8	// Read(12)
-// #define CCISS_WRITE	0xaa	// Write(12)
- #define CCISS_READ   0x28    // Read(10)
- #define CCISS_WRITE  0x2a    // Write(10)
+/* 12 byte commands not implemented in firmware yet.  */
+/* #define CCISS_READ 	0xa8	Read(12)	*/
+/* #define CCISS_WRITE	0xaa	Write(12) 	*/
+ #define CCISS_READ   0x28    /* Read(10) */
+ #define CCISS_WRITE  0x2a    /* Write(10) */
 
-// BMIC commands 
+/* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27
 #define BMIC_CACHE_FLUSH 0xc2
-#define CCISS_CACHE_FLUSH 0x01	//C2 was already being used by CCISS
+#define CCISS_CACHE_FLUSH 0x01	/* 0xC2 was already being used by CCISS */
 
-//Command List Structure
+/* Command List Structure */
 typedef union _SCSI3Addr_struct {
    struct {
     BYTE Dev;
     BYTE Bus:6;
-    BYTE Mode:2;        // b00
+    BYTE Mode:2;        /* b00 */
   } PeripDev;
    struct {
     BYTE DevLSB;
     BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
+    BYTE Mode:2;        /* b01 */
   } LogDev;
    struct {
     BYTE Dev:5;
     BYTE Bus:3;
     BYTE Targ:6;
-    BYTE Mode:2;        // b10
+    BYTE Mode:2;        /* b10 */
   } LogUnit;
 } SCSI3Addr_struct;
 
@@ -154,7 +155,7 @@
   DWORD             TargetId:24;
   DWORD             Bus:6;
   DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
+  SCSI3Addr_struct  Target[2]; /* 2 level target device addr */
 } PhysDevAddr_struct;
   
 typedef struct _LogDevAddr_struct {
@@ -205,8 +206,8 @@
   }Common_Info;
   struct{
     BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
+    BYTE  offense_size;	/* size of offending entry 	*/
+    BYTE  offense_num; 	/* byte # of offense 0-base 	*/
     DWORD offense_value;
   }Invalid_Cmd;
 }MoreErrInfo_struct;
@@ -240,12 +241,13 @@
   struct _CommandList_struct *next;
   struct request *	   rq;
   struct completion *waiting;
+  int	 retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif
 } CommandList_struct;
 
-//Configuration Table Structure
+/* Configuration Table Structure */
 typedef struct _HostWrite_struct {
   DWORD TransportRequest;
   DWORD Reserved;
@@ -266,4 +268,4 @@
   DWORD            HeartBeat;
 } CfgTable_struct;
 #pragma pack()	 
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
diff -urN linux-2.4.21-pre1/drivers/block/cciss_scsi.c linux-2.4.21-pre2/drivers/block/cciss_scsi.c
--- linux-2.4.21-pre1/drivers/block/cciss_scsi.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/block/cciss_scsi.c	Wed Dec 18 14:16:27 2002
@@ -1,7 +1,7 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
- *
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
+ *    
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net 
  *
  *    Author: Stephen M. Cameron
  */
@@ -233,8 +233,8 @@
 		printk( "cciss: %d scsi commands are still outstanding.\n",
 			CMD_STACK_SIZE - stk->top);
 		// BUG();
-		printk("WE HAVE A BUG HERE!!! stk=%p\n",
-			stk);
+		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+			(unsigned int) stk);
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -896,7 +896,7 @@
 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	memcpy(cp->Request.CDB, cdb, cdblen);
-	cp->Request.Timeout = 1000;		// guarantee completion.
+	cp->Request.Timeout = 0;	// No timeout
 	cp->Request.CDBLen = cdblen;
 	cp->Request.Type.Type = TYPE_CMD;
 	cp->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1414,7 +1414,7 @@
 
 	// Fill in the request block...
 
-	cp->Request.Timeout = 1000; // guarantee completion
+	cp->Request.Timeout = 0; // No timeout 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
 	cp->Request.CDBLen = cmd->cmd_len;
@@ -1578,14 +1578,14 @@
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned long flags;
+	unsigned int flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
 	CPQ_TAPE_LOCK(ctlr, flags);
 	size = sprintf(buffer + *len,
-		"       Sequential access devices: %d\n\n",
-			ccissscsi[ctlr].ndevices);
+		"Sequential access devices: %d\n\n",
+		 ccissscsi[ctlr].ndevices);
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 	*pos += size; *len += size;
 }
diff -urN linux-2.4.21-pre1/drivers/block/cciss_scsi.h linux-2.4.21-pre2/drivers/block/cciss_scsi.h
--- linux-2.4.21-pre1/drivers/block/cciss_scsi.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/block/cciss_scsi.h	Wed Dec 18 14:16:27 2002
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 #ifdef CONFIG_CISS_SCSI_TAPE
diff -urN linux-2.4.21-pre1/drivers/block/cpqarray.c linux-2.4.21-pre2/drivers/block/cpqarray.c
--- linux-2.4.21-pre1/drivers/block/cpqarray.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/block/cpqarray.c	Wed Dec 18 14:16:27 2002
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
  *
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
@@ -41,13 +41,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.21)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,21)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.21");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
 MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -162,6 +162,7 @@
 static int ida_release(struct inode *inode, struct file *filep);
 static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
 static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+static int ida_ctlr_big_ioctl( int ctlr, int dsk, ida_big_ioctl_t *io);
 
 static void do_ida_request(request_queue_t *q);
 static void start_io(ctlr_info_t *h);
@@ -279,8 +280,7 @@
 
 	for(i=0; i<=h->highest_lun; i++) {
 		drv = &h->drv[i];
-		if(drv->nr_blks != 0)
-		{
+		if(drv->nr_blks != 0) {
 		    	size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
 				ctlr, i, drv->blk_size, drv->nr_blks);
 			pos += size; len += size;
@@ -293,7 +293,8 @@
 
 	c = h->reqQ;
 	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->reqQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -302,7 +303,8 @@
 
 	c = h->cmpQ;
 	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->cmpQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -369,8 +371,7 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    */
 	memset(buff, 0 , 4);
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
@@ -399,8 +400,7 @@
 {
 	char buff[4]; 
 
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cpqarray: device appears to "
 			"already be removed \n");
 		return;
@@ -409,8 +409,7 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    
 	 * no data returned, but don't want to send NULL to sendcmd */	
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
@@ -488,15 +487,14 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	/* fill in default block size */
 	for(j=0;j<256;j++)
-                hba[i]->hardsizes[j] = BLOCK_SIZE;
+                hba[i]->hardsizes[j] = hba[i]->drv[j].blk_size;
 
 	sprintf(hba[i]->devname, "ida%d", i);
         hba[i]->ctlr = i;
 	/* Initialize the pdev driver private data */
 	pci_set_drvdata(pdev, hba[i]);
 
-	if (cpqarray_pci_init(hba[i], pdev) != 0)
-	{
+	if (cpqarray_pci_init(hba[i], pdev) != 0) {
 		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
@@ -510,8 +508,7 @@
 	
 	/* If this successful it should insure that we are the only */
 	/* instance of the driver */	
-	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) 
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
         	printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
                                 MAJOR_NR+i);
                 release_io_mem(hba[i]);
@@ -522,8 +519,8 @@
 	
 	hba[i]->access.set_intr_mask(hba[i], 0);
 	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) 
-	{
+		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+				hba[i]->devname, hba[i])) {
 
 		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
 				hba[i]->intr, hba[i]->devname);
@@ -538,8 +535,7 @@
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
 				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
 		
-	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
-	{
+	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
 		if(hba[i]->cmd_pool_bits)
 			kfree(hba[i]->cmd_pool_bits);
 		if(hba[i]->cmd_pool)
@@ -583,6 +579,7 @@
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; 
+	hba[i]->gendisk.fops = &ida_fops;
 	
 		/* Get on the disk list */
 	add_gendisk(&(hba[i]->gendisk));
@@ -622,8 +619,7 @@
 	pci_register_driver(&cpqarray_pci_driver);
 	cpqarray_eisa_detect();
 
-	for(i=0; i< MAX_CTLR; i++)
-        {
+	for(i=0; i< MAX_CTLR; i++) {
 		if (hba[i] != NULL)
 			num_cntlrs_reg++;
 	}
@@ -634,13 +630,10 @@
 static int alloc_cpqarray_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if(hba[i]==NULL) {
 				printk(KERN_ERR "cpqarray: out of memory.\n");
 				return (-1);
 			}
@@ -674,8 +667,7 @@
 
 	pci_read_config_word(pdev, PCI_COMMAND, &command);
 	/* check to see if controller has been disabled */
-	if(!(command & 0x02))
-	{
+	if(!(command & 0x02)) {
 		printk(KERN_WARNING "cpqarray: controller appears to be disabled\n");
 		return(-1);
 	}
@@ -688,13 +680,11 @@
 	for(i=0; i<6; i++)
 		addr[i] = pci_resource_start(pdev, i);
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
 		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) {
 		printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
 		return -1;
 	}
@@ -719,18 +709,16 @@
 );
 
 	c->intr = irq;
-	for(i=0; i<6; i++)
-	{
-		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
-		{ /* IO space */  
+	for(i=0; i<6; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { 
+			/* IO space */  
 			c->io_mem_addr = addr[i];
 			c->io_mem_length = pci_resource_end(pdev, i) 
 				- pci_resource_start(pdev, i) +1; 
 			// printk("IO Value found addr[%d] %lx %lx\n",
 			//		i, c->io_mem_addr, c->io_mem_length);
 			if(!request_region( c->io_mem_addr, c->io_mem_length,
-				"cpqarray"))
-			{
+				"cpqarray")) {
 				printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length);
 				c->io_mem_addr = 0;
 				c->io_mem_length = 0;
@@ -740,7 +728,8 @@
 	}	
 	c->paddr = 0;
 	for(i=0; i<6; i++)
-		if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) {
+		if (!(pci_resource_flags(pdev, i) & 
+					PCI_BASE_ADDRESS_SPACE_IO)) {
 			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
@@ -843,8 +832,7 @@
 		hba[ctlr]->io_mem_length = 0x7FF;		
 		if(!request_region( hba[ctlr]->io_mem_addr, 
 					hba[ctlr]->io_mem_length, 
-				"cpqarray"))
-		{
+				"cpqarray")) {
 			printk( KERN_WARNING "cpqarray: I/0 range already in use addr = %lx length=%ld\n",
 			 hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length);
 			free_hba(ctlr);
@@ -854,10 +842,14 @@
 		 * Read the config register to find our interrupt
 		 */
 		intr = inb(eisa[i]+0xCC0) >> 4;
-		if (intr & 1) intr = 11;
-		else if (intr & 2) intr = 10;
-		else if (intr & 4) intr = 14;
-		else if (intr & 8) intr = 15;
+		if (intr & 1) 
+			intr = 11;
+		else if (intr & 2) 
+			intr = 10;
+		else if (intr & 4) 
+			intr = 14;
+		else if (intr & 8) 
+			intr = 15;
 		
 		hba[ctlr]->intr = intr;
 		sprintf(hba[ctlr]->devname, "ida%d", ctlr);
@@ -894,19 +886,18 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
-		return -ENXIO;
-
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
 	 * so array config can still work.  I don't think I really like this,
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
-	if (suser()
-		&& hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0 
-		&& MINOR(inode->i_rdev) != 0)
-		return -ENXIO;
+	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) {
+		if (MINOR(inode->i_rdev) != 0)
+			return -ENXIO;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
 
 	hba[ctlr]->drv[dsk].usage_count++;
 	hba[ctlr]->usage_count++;
@@ -947,7 +938,8 @@
 static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
 {
 	if (c && c->next != c) {
-		if (*Qptr == c) *Qptr = c->next;
+		if (*Qptr == c) 
+			*Qptr = c->next;
 		c->prev->next = c->next;
 		c->next->prev = c->prev;
 	} else {
@@ -985,8 +977,7 @@
 	if (creq->nr_segments > SG_MAX)
 		BUG();
 
-	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-	{
+	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
 		printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
 				h->ctlr, creq->rq_dev, creq);
 		blkdev_dequeue_request(creq);
@@ -1036,8 +1027,7 @@
 		bh = bh->b_reqnext;
 	}
 	/* Now do all the DMA Mappings */
-	for( i=0; i < seg; i++)
-	{
+	for( i=0; i < seg; i++) {
 		c->req.sg[i].size = tmp_sg[i].length;
 		c->req.sg[i].addr = (__u32) pci_map_page(
                 		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
@@ -1131,7 +1121,8 @@
 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
 		ok = 0;	
 	}
-	if (timeout) ok = 0;
+	if (timeout) 
+		ok = 0;
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
@@ -1192,15 +1183,14 @@
                                  *  But rcode = 0.
                                  */
 
-				if((a1 & 0x03) && (c->req.hdr.rcode == 0))
-                                {
+				if((a1 & 0x03) && (c->req.hdr.rcode == 0)) {
                                 	c->req.hdr.rcode = RCODE_INVREQ;
                                 }
 				if (c->type == CMD_RWREQ) {
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
 				} else if (c->type == CMD_IOCTL_PEND) {
-					c->type = CMD_IOCTL_DONE;
+					complete(c->waiting);
 				}
 				continue;
 			}
@@ -1238,8 +1228,6 @@
 	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
 	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
 	int error;
-	ida_ioctl_t *io = (ida_ioctl_t*)arg;
-	ida_ioctl_t my_io;
 
 	switch(cmd) {
 	case HDIO_GETGEO:
@@ -1286,9 +1274,14 @@
 	}
 
 	case IDAGETDRVINFO:
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+	}
 	case BLKGETSIZE:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, 
 			(unsigned long *)arg);
 	case BLKGETSIZE64:
@@ -1296,16 +1289,42 @@
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
-		if (!suser()) return -EPERM;
-		error = copy_from_user(&my_io, io, sizeof(my_io));
-		if (error) return error;
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
+		ida_ioctl_t my_io;
+
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
-		if (error) return error;
-		if(copy_to_user(io, &my_io, sizeof(my_io)))
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
 			return -EFAULT;
-		return error;
+		return 0;
+	}
+	case IDABIGPASSTHRU:
+	{
+
+		ida_big_ioctl_t *io = (ida_big_ioctl_t*)arg;
+		ida_big_ioctl_t my_io;
+		
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
+		error = ida_ctlr_big_ioctl(ctlr, dsk, &my_io);
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
+		return 0;
+	}
 	case IDAGETCTLRSIG:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
 		return 0;
 	case IDAREVALIDATEVOLS:
@@ -1319,7 +1338,8 @@
 		
 		ida_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
@@ -1347,8 +1367,7 @@
 
 		/* count partitions 1 to 15 with sizes > 0 */
 		start = (dsk << NWD_SHIFT); 	
-		for(i=1; i <IDA_MAX_PART; i++)
-		{
+		for(i=1; i <IDA_MAX_PART; i++) {
 			int minor = start+i;
 			if(hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
@@ -1394,6 +1413,7 @@
 	void *p = NULL;
 	unsigned long flags;
 	int error;
+	DECLARE_COMPLETION(wait);
 
 	if ((c = cmd_alloc(h, 0)) == NULL)
 		return -ENOMEM;
@@ -1411,8 +1431,7 @@
 	switch(io->cmd) {
 	case PASSTHRU_A:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
 			error = -ENOMEM; 
 			cmd_free(h, c, 0); 
 			return(error);
@@ -1431,11 +1450,11 @@
 		c->req.hdr.sg_cnt = 1;
 		break;
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case READ_FLASH_ROM:
 	case SENSE_CONTROLLER_PERFORMANCE:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1452,8 +1471,7 @@
 	case COLLECT_BUFFER:
 	case WRITE_FLASH_ROM:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
- 		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1474,7 +1492,9 @@
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 		c->req.hdr.sg_cnt = 1;
 	}
-	
+
+	c->waiting = &wait;
+
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&h->reqQ, c);
@@ -1483,8 +1503,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	/* Unmap the DMA  */
 	pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size, 
@@ -1496,6 +1515,7 @@
                                 sizeof(ida_ioctl_t),
                                 PCI_DMA_BIDIRECTIONAL);
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
@@ -1520,6 +1540,175 @@
 }
 
 /*
+ * ida_ctlr_big_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  
+ */
+static int ida_ctlr_big_ioctl(int ctlr, int dsk, ida_big_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	__u8   *scsi_param = NULL;
+	__u8	*buff[SG_MAX] = {NULL,};
+	size_t	buff_size[SG_MAX];
+	__u8	sg_used = 0;
+	unsigned long flags;
+	int error = 0;
+	int i;
+	DECLARE_COMPLETION(wait);
+
+	/* Check kmalloc limits  using all SGs */
+	if( io->buff_malloc_size > IDA_MAX_KMALLOC_SIZE)
+		return -EINVAL;
+	if( io->buff_size > io->buff_malloc_size * SG_MAX)
+		return -EINVAL;
+	if ((c = cmd_alloc(h, 0)) == NULL)
+		return -ENOMEM;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.cmd = io->cmd;
+	c->req.hdr.blk = io->blk;
+	c->req.hdr.blk_cnt = io->blk_cnt;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	/* for passthru_a the scsi command is in another record */
+	if (io->cmd == PASSTHRU_A) {
+
+		if (io->scsi_param == NULL)
+		{
+			error = -EINVAL;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+		scsi_param = kmalloc(sizeof(scsi_param_t),  GFP_KERNEL);
+		if (scsi_param == NULL) {
+			error = -ENOMEM;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+
+		/* copy the scsi command to get passed thru */ 	
+		if (copy_from_user(scsi_param, io->scsi_param, 
+					sizeof(scsi_param_t))) {	
+			kfree(scsi_param);
+			cmd_free(h, c, 0);
+			return -EFAULT;
+		}
+
+		/* with this command the scsi command is seperate */
+		c->req.hdr.blk = pci_map_single(h->pci_dev, scsi_param,
+				sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* fill in the SG entries */
+	/* create buffers if we need to */ 
+	if(io->buff_size > 0) {
+		size_t size_left_alloc = io->buff_size;
+		__u8 *data_ptr = io->buff;
+
+		while(size_left_alloc > 0) {
+			buff_size[sg_used] = (size_left_alloc 
+					> io->buff_malloc_size)
+				? io->buff_malloc_size : size_left_alloc;
+			buff[sg_used] = kmalloc( buff_size[sg_used], 
+					GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				error = -ENOMEM;
+				goto ida_alloc_cleanup;
+			}
+			if(io->xfer_type & IDA_XFER_WRITE) {
+				/* Copy the data into the buffer created */
+				if (copy_from_user(buff[sg_used], data_ptr,
+						buff_size[sg_used])) {
+					error = -EFAULT;
+					goto ida_alloc_cleanup;
+				}
+			}
+			/* put the data into the scatter gather list */
+			c->req.sg[sg_used].size = buff_size[sg_used];
+			c->req.sg[sg_used].addr = pci_map_single(h->pci_dev, 
+					buff[sg_used], buff_size[sg_used],
+					 PCI_DMA_BIDIRECTIONAL);
+			
+			size_left_alloc -= buff_size[sg_used];
+			data_ptr += buff_size[sg_used];
+			sg_used++;
+		}
+	}
+	c->req.hdr.sg_cnt = sg_used;
+
+	c->waiting = &wait;
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* Wait for completion */
+	wait_for_completion(&wait);
+	/* Unmap the DMA  */
+	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+		pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				c->req.sg[i].size, PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* if we are reading data from the hardware copy it back to user */
+	if (io->xfer_type & IDA_XFER_READ) {
+		__u8	*data_ptr = io->buff;
+		int i;
+
+	    	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+			if (copy_to_user(data_ptr, buff[i], buff_size[i])) { 
+				error = -EFAULT;
+				goto ida_alloc_cleanup;
+			}
+			data_ptr += buff_size[i];
+			
+		}
+
+	}
+
+	io->rcode = c->req.hdr.rcode;
+
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		/* copy the scsi_params back to the user */ 
+		if( copy_to_user(io->scsi_param, scsi_param, 
+					sizeof(scsi_param_t))) {
+			error = -EFAULT;	
+		}
+		kfree(scsi_param);
+	}
+	cmd_free(h, c, 0);
+	return(error);
+	
+ida_alloc_cleanup:
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		kfree(scsi_param);
+	}
+	for (i=0; i<sg_used; i++) {
+		if(buff[sg_used] != NULL) {	
+			pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				buff_size[sg_used], PCI_DMA_BIDIRECTIONAL);
+			kfree(buff[sg_used]);
+		}
+	}	
+	cmd_free(h, c, 0);
+	return(error);
+}
+/*
  * Commands are pre-allocated in a large block.  Here we use a simple bitmap
  * scheme to suballocte them to the driver.  Operations that are not time
  * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
@@ -1720,7 +1909,7 @@
 	hba[ctlr]->gendisk.nr_real = 0;
 
 	for(i=0;i<256;i++)
-                hba[ctlr]->hardsizes[i] = BLOCK_SIZE;
+                hba[ctlr]->hardsizes[i] = 0;
 	/*
 	 * Tell the array controller not to give us any interrupts while
 	 * we check the new geometry.  Then turn interrupts back on when
@@ -1752,8 +1941,7 @@
 
 	spin_lock_irqsave(&io_request_lock, flags);
 	/* make sure logical volume is NOT is use */
-	if( h->drv[logvol].usage_count > 1)
-	{
+	if( h->drv[logvol].usage_count > 1) {
 		spin_unlock_irqrestore(&io_request_lock, flags);
                 return -EBUSY;
 	}
@@ -1763,21 +1951,21 @@
 	/* invalidate the devices and deregister the disk */ 
 	max_p = gdev->max_p;
 	start = logvol << gdev->minor_shift;
-	for (i=max_p-1; i>=0; i--)
-	{
+	for (i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		// printk("invalidating( %d %d)\n", ctlr, minor);
 		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
 		/* so open will now fail */
 		hba[ctlr]->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
 	}
 	/* check to see if it was the last disk */
-	if (logvol == h->highest_lun)
-	{
+	if (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
 		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++)
-		{
+		for(i=0; i<h->highest_lun; i++) {
 			/* if the disk has size > 0, it is available */
 			if (hba[ctlr]->sizes[i << gdev->minor_shift] != 0)
 				newhighest = i;
@@ -1789,7 +1977,8 @@
 	gdev->nr_real = h->highest_lun+1; 
 	/* zero out the disk size info */ 
 	h->drv[logvol].nr_blks = 0;
-	h->drv[logvol].blk_size = BLOCK_SIZE;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].blk_size = 0;
 	return(0);
 
 }
@@ -1806,6 +1995,7 @@
 	cmdlist_t *c;
 	unsigned long flags;
 	ctlr_info_t *info_p = hba[ctlr];
+	DECLARE_COMPLETION(wait);
 
 	c = cmd_alloc(info_p, 0);
 	if(!c)
@@ -1835,6 +2025,7 @@
 	c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, 
 		buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 
+	c->waiting = &wait;
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&info_p->reqQ, c);
@@ -1843,8 +2034,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	if (c->req.hdr.rcode & RCODE_FATAL) {
 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
@@ -1885,14 +2075,12 @@
 		return -EINVAL;
 
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
 	}
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
@@ -1905,8 +2093,7 @@
 	 */
 	ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
 		ctlr, id_lstatus_buf, size, 0, 0, logvol);
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 			/*
 			   If can't get logical drive status, set
 			   the logical drive map to 0, so the
@@ -1922,8 +2109,7 @@
 	/*
 		   Make sure the logical drive is configured
 	 */
-	if (id_lstatus_buf->status == LOG_NOT_CONF) 
-	{
+	if (id_lstatus_buf->status == LOG_NOT_CONF) {
 		printk(KERN_WARNING "cpqarray: c%dd%d array not configured\n",
 			ctlr, logvol); 
 		kfree(id_lstatus_buf);
@@ -1937,8 +2123,7 @@
 			   logical drive won't be set and
 			   idastubopen will return error. 
 			 */
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 		printk(KERN_WARNING "cpqarray: c%dd%d unable to ID logical volume\n",
 			ctlr,logvol);
 		kfree(id_lstatus_buf);
@@ -1963,8 +2148,7 @@
 	max_p = gdev->max_p;
 	start = logvol<< gdev->minor_shift;
 	
-	for(i=max_p-1; i>=0; i--) 
-	{
+	for(i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
 		gdev->part[minor].start_sect = 0;
@@ -1972,6 +2156,7 @@
 	
 		/* reset the blocksize so we can read the partition table */
 		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = drv->blk_size;
 	}
 	++hba[ctlr]->log_drives;
 	gdev->nr_real = info_p->highest_lun + 1;
@@ -2075,8 +2260,7 @@
 	/* Command does not return anything, but idasend command needs a 
 		buffer */
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf==NULL)
-	{
+	if(id_ctlr_buf==NULL) {
 		printk(KERN_WARNING "cpqarray: Out of memory. "
 			"Unable to start background processing.\n");
 		return;
@@ -2110,23 +2294,20 @@
 	info_p->log_drv_map = 0;	
 	
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf == NULL)
-	{
+	if(id_ctlr_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
@@ -2134,8 +2315,7 @@
 	}
 
 	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
-	if(sense_config_buf == NULL)
-	{
+	if(sense_config_buf == NULL) {
 		kfree(id_lstatus_buf);
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
@@ -2285,10 +2465,8 @@
 
         pci_unregister_driver(&cpqarray_pci_driver);
         /* double check that all controller entrys have been removed */
-        for (i=0; i< MAX_CTLR; i++)
-        {
-                if (hba[i] != NULL)
-                {
+        for (i=0; i< MAX_CTLR; i++) {
+                if (hba[i] != NULL) {
                         printk(KERN_WARNING "cpqarray: had to remove"
                                         " controller %d\n", i);
                         cpqarray_remove_one_eisa(i);
diff -urN linux-2.4.21-pre1/drivers/block/ida_cmd.h linux-2.4.21-pre2/drivers/block/ida_cmd.h
--- linux-2.4.21-pre1/drivers/block/ida_cmd.h	Fri Nov  2 17:45:42 2001
+++ linux-2.4.21-pre2/drivers/block/ida_cmd.h	Wed Dec 18 14:16:27 2002
@@ -82,7 +82,6 @@
 
 #define CMD_RWREQ	0x00
 #define CMD_IOCTL_PEND	0x01
-#define CMD_IOCTL_DONE	0x02
 
 typedef struct cmdlist {
 	chdr_t	hdr;
@@ -94,6 +93,7 @@
 	struct cmdlist *prev;
 	struct cmdlist *next;
 	struct request *rq;
+	struct completion *waiting;
 	int type;
 } cmdlist_t;
 	
@@ -318,6 +318,8 @@
 	__u8	reserved[510];
 } mp_delay_t;
 
+#define SENSE_SURF_STATUS	0x70
+
 #define PASSTHRU_A	0x91
 typedef struct {
 	__u8	target;
diff -urN linux-2.4.21-pre1/drivers/block/ida_ioctl.h linux-2.4.21-pre2/drivers/block/ida_ioctl.h
--- linux-2.4.21-pre1/drivers/block/ida_ioctl.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/block/ida_ioctl.h	Wed Dec 18 14:16:27 2002
@@ -34,6 +34,7 @@
 #define IDADEREGDISK		0x33333434
 #define IDAREGNEWDISK		0x34343535
 #define IDAGETLOGINFO		0x35353636
+#define IDABIGPASSTHRU          0x36363535
 
 typedef struct _ida_pci_info_struct
 {
@@ -94,4 +95,27 @@
 	} c;
 } ida_ioctl_t;
 
+#define IDA_MAX_KMALLOC_SIZE 128000
+
+/* transfer type of the commands */
+#define IDA_XFER_NONE	0x00
+#define IDA_XFER_READ	0x01
+#define IDA_XFER_WRITE	0x02
+#define IDA_XFER_BOTH	0x03
+
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+	__u32	blk;
+	__u16	blk_cnt;
+
+	__u8	xfer_type;
+	__u8    *buff;
+	size_t	buff_size;
+	__u32	buff_malloc_size;
+	scsi_param_t *scsi_param; /* used only for PASSTHRU_A */
+
+} ida_big_ioctl_t;
+
 #endif /* IDA_IOCTL_H */
diff -urN linux-2.4.21-pre1/drivers/block/ll_rw_blk.c linux-2.4.21-pre2/drivers/block/ll_rw_blk.c
--- linux-2.4.21-pre1/drivers/block/ll_rw_blk.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/block/ll_rw_blk.c	Wed Dec 18 14:16:27 2002
@@ -394,7 +394,7 @@
 	unsigned long flags;
 	/* Several broken drivers assume that this function doesn't sleep,
 	 * this causes system hangs during boot.
-	 * As a temporary fix, make the the function non-blocking.
+	 * As a temporary fix, make the function non-blocking.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
 	while (q->nr_requests < nr_requests) {
diff -urN linux-2.4.21-pre1/drivers/block/nbd.c linux-2.4.21-pre2/drivers/block/nbd.c
--- linux-2.4.21-pre1/drivers/block/nbd.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/block/nbd.c	Wed Dec 18 14:16:27 2002
@@ -26,6 +26,8 @@
  *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
  * 01-12-6 Fix deadlock condition by making queue locks independant of
  *   the transmit lock. <steve@chygwyn.com>
+ * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
+ *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
  *
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
  * why not: would need verify_area and friends, would share yet another 
@@ -101,9 +103,12 @@
 	oldfs = get_fs();
 	set_fs(get_ds());
 
+	/* Allow interception of SIGKILL only
+	 * Don't allow other signals to interrupt the transmission */
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
+	sigdelsetmask(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
@@ -126,6 +131,17 @@
 		else
 			result = sock_recvmsg(sock, &msg, size, 0);
 
+		if (signal_pending(current)) {
+			siginfo_t info;
+			spin_lock_irqsave(&current->sigmask_lock, flags);
+			printk(KERN_WARNING "NBD (pid %d: %s) got signal %d\n",
+				current->pid, current->comm, 
+				dequeue_signal(&current->blocked, &info));
+			spin_unlock_irqrestore(&current->sigmask_lock, flags);
+			result = -EINTR;
+			break;
+		}
+
 		if (result <= 0) {
 #ifdef PARANOIA
 			printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n",
@@ -150,7 +166,7 @@
 
 void nbd_send_req(struct nbd_device *lo, struct request *req)
 {
-	int result;
+	int result = -1;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
@@ -164,6 +180,10 @@
 
 	down(&lo->tx_lock);
 
+	if (!sock || !lo->sock) {
+		FAIL("Attempted sendmsg to closed socket\n");
+	}
+
 	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
 	if (result <= 0)
 		FAIL("Sendmsg failed for control.");
@@ -345,10 +365,28 @@
 		spin_unlock_irq(&io_request_lock);
 
 		spin_lock(&lo->queue_lock);
+		if (!lo->file) {
+			spin_unlock(&lo->queue_lock);
+			printk(KERN_ERR "nbd: failed between accept and semaphore, file lost\n");
+			req->errors++;
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
+
 		list_add_tail(&req->queue, &lo->queue_head);
 		spin_unlock(&lo->queue_lock);
 
 		nbd_send_req(lo, req);
+		if (req->errors) {
+			printk(KERN_ERR "nbd: nbd_send_req failed\n");
+			spin_lock(&lo->queue_lock);
+			list_del(&req->queue);
+			spin_unlock(&lo->queue_lock);
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
 
 		spin_lock_irq(&io_request_lock);
 		continue;
@@ -397,12 +435,14 @@
 			printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
 			return -EBUSY;
 		}
-		spin_unlock(&lo->queue_lock);
 		file = lo->file;
-		if (!file)
+		if (!file) {
+			spin_unlock(&lo->queue_lock);
 			return -EINVAL;
+		}
 		lo->file = NULL;
 		lo->sock = NULL;
+		spin_unlock(&lo->queue_lock);
 		fput(file);
 		return 0;
 	case NBD_SET_SOCK:
@@ -443,6 +483,26 @@
 		if (!lo->file)
 			return -EINVAL;
 		nbd_do_it(lo);
+		/* on return tidy up in case we have a signal */
+		/* Forcibly shutdown the socket causing all listeners
+		 * to error
+		 *
+		 * FIXME: This code is duplicated from sys_shutdown, but
+		 * there should be a more generic interface rather than
+		 * calling socket ops directly here */
+		down(&lo->tx_lock);
+		printk(KERN_WARNING "nbd: shutting down socket\n");
+		lo->sock->ops->shutdown(lo->sock, SEND_SHUTDOWN|RCV_SHUTDOWN);
+		lo->sock = NULL;
+		up(&lo->tx_lock);
+		spin_lock(&lo->queue_lock);
+		file = lo->file;
+		lo->file = NULL;
+		spin_unlock(&lo->queue_lock);
+		nbd_clear_que(lo);
+		printk(KERN_WARNING "nbd: queue cleared\n");
+		if (file)
+			fput(file);
 		return lo->harderror;
 	case NBD_CLEAR_QUE:
 		nbd_clear_que(lo);
@@ -523,7 +583,7 @@
 		init_MUTEX(&nbd_dev[i].tx_lock);
 		nbd_blksizes[i] = 1024;
 		nbd_blksize_bits[i] = 10;
-		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
+		nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */
 		nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
 		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
 				nbd_bytesizes[i]>>9);
diff -urN linux-2.4.21-pre1/drivers/char/Config.in linux-2.4.21-pre2/drivers/char/Config.in
--- linux-2.4.21-pre1/drivers/char/Config.in	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/char/Config.in	Wed Dec 18 14:16:27 2002
@@ -155,6 +155,7 @@
       bool '  Support for console on line printer' CONFIG_LP_CONSOLE
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+   dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
 fi
 
 if [ "$CONFIG_PPC64" ] ; then 
diff -urN linux-2.4.21-pre1/drivers/char/Makefile linux-2.4.21-pre2/drivers/char/Makefile
--- linux-2.4.21-pre1/drivers/char/Makefile	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/char/Makefile	Wed Dec 18 14:16:27 2002
@@ -204,6 +204,7 @@
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
+obj-$(CONFIG_TIPAR) += tipar.o
 
 ifeq ($(CONFIG_INPUT),y)
 obj-y += joystick/js.o
diff -urN linux-2.4.21-pre1/drivers/char/agp/agp.h linux-2.4.21-pre2/drivers/char/agp/agp.h
--- linux-2.4.21-pre1/drivers/char/agp/agp.h	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/char/agp/agp.h	Wed Dec 18 14:16:27 2002
@@ -87,6 +87,7 @@
 	u32 *gatt_table;
 	u32 *gatt_table_real;
 	unsigned long scratch_page;
+	unsigned long scratch_page_real;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
 	u32 mode;
@@ -99,7 +100,6 @@
 	int needs_scratch_page;
 	int aperture_size_idx;
 	int num_aperture_sizes;
-	int num_of_masks;
 	int capndx;
 	int cant_use_aperture;
 
diff -urN linux-2.4.21-pre1/drivers/char/agp/agpgart_be.c linux-2.4.21-pre2/drivers/char/agp/agpgart_be.c
--- linux-2.4.21-pre1/drivers/char/agp/agpgart_be.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/char/agp/agpgart_be.c	Wed Dec 18 14:16:27 2002
@@ -209,7 +209,6 @@
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] &= ~(0x00000fff);
 			agp_bridge.agp_destroy_page((unsigned long)
 					 phys_to_virt(curr->memory[i]));
 		}
@@ -262,10 +261,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[i] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[i]),
-						  type);
+		new->memory[i] = virt_to_phys((void *) new->memory[i]);
 		new->page_count++;
 	}
 
@@ -311,9 +307,6 @@
 
 int agp_copy_info(agp_kern_info * info)
 {
-	unsigned long page_mask = 0;
-	int i;
-
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
@@ -329,11 +322,7 @@
 	info->max_memory = agp_bridge.max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
 	info->cant_use_aperture = agp_bridge.cant_use_aperture;
-
-	for(i = 0; i < agp_bridge.num_of_masks; i++)
-		page_mask |= agp_bridge.mask_memory(page_mask, i);
-
-	info->page_mask = ~page_mask;
+	info->page_mask = ~0UL;
 	return 0;
 }
 
@@ -731,7 +720,8 @@
 		mem->is_flushed = TRUE;
 	}
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		agp_bridge.gatt_table[j] = mem->memory[i];
+		agp_bridge.gatt_table[j] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 
 	agp_bridge.tlb_flush(mem);
@@ -976,7 +966,8 @@
    	CACHE_FLUSH();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
-			 I810_PTE_BASE + (j * 4), mem->memory[i]);
+			 I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 	}
 	CACHE_FLUSH();
 
@@ -1042,10 +1033,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[0] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[0]),
-						  type);
+		new->memory[0] = virt_to_phys((void *) new->memory[0]);
 		new->page_count = 1;
 	   	new->num_scratch_pages = 1;
 	   	new->type = AGP_PHYS_MEMORY;
@@ -1079,7 +1067,6 @@
 	intel_i810_private.i810_dev = i810_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 2;
 	agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1282,7 +1269,8 @@
 	CACHE_FLUSH();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 
 	CACHE_FLUSH();
 
@@ -1343,7 +1331,7 @@
 			return(NULL);
 		}
 
-		nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+		nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
 		nw->page_count = 1;
 		nw->num_scratch_pages = 1;
 		nw->type = AGP_PHYS_MEMORY;
@@ -1359,7 +1347,6 @@
 	intel_i830_private.i830_dev = i830_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 3;
 	agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1841,7 +1828,6 @@
 static int __init intel_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
 	agp_bridge.size_type = U16_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -1874,7 +1860,6 @@
 static int __init intel_815_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_815_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1907,7 +1892,6 @@
 static int __init intel_820_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 7;
@@ -1940,7 +1924,6 @@
 static int __init intel_830mp_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 4;
@@ -1972,7 +1955,6 @@
 static int __init intel_840_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2005,7 +1987,6 @@
 static int __init intel_845_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2038,7 +2019,6 @@
 static int __init intel_850_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2071,7 +2051,6 @@
 static int __init intel_860_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2191,7 +2170,6 @@
 static int __init via_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = via_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) via_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2305,7 +2283,6 @@
 static int __init sis_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = sis_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2643,7 +2620,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -2689,7 +2667,6 @@
 static int __init amd_irongate_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_irongate_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2790,7 +2767,7 @@
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		addr = mem->memory[i];
+		addr = agp_bridge.mask_memory(mem->memory[i], mem->type);
 
 		tmp = addr;
 		BUG_ON(tmp & 0xffffff0000000ffc);
@@ -3155,7 +3132,6 @@
 static int __init amd_8151_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_8151_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_8151_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3393,7 +3369,6 @@
 static int __init ali_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = ali_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3807,7 +3782,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -3964,7 +3940,6 @@
 	serverworks_private.svrwrks_dev = pdev;
 
 	agp_bridge.masks = serverworks_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) serverworks_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -4362,7 +4337,6 @@
 static int __init hp_zx1_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = hp_zx1_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.dev_private_data = NULL;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.needs_scratch_page = FALSE;
@@ -4485,12 +4459,6 @@
 		"AMD",
 		"761",
 		amd_irongate_setup },
-	{ PCI_DEVICE_ID_AMD_762_0,
-		PCI_VENDOR_ID_AMD,
-		AMD_762,
-		"AMD",
-		"760MP",
-		amd_irongate_setup },
 	{ 0,
 		PCI_VENDOR_ID_AMD,
 		AMD_GENERIC,
@@ -4556,7 +4524,7 @@
 		 INTEL_I845_G,
 		 "Intel",
 		 "i845G",
-		 intel_830mp_setup },
+		 intel_845_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -5083,17 +5051,17 @@
 	}
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
+		unsigned long addr;
+		addr = agp_bridge.agp_alloc_page();
 
-		if (agp_bridge.scratch_page == 0) {
+		if (addr == 0) {
 			printk(KERN_ERR PFX "unable to get memory for "
 			       "scratch page.\n");
 			return -ENOMEM;
 		}
+		agp_bridge.scratch_page_real = virt_to_phys((void *) addr);
 		agp_bridge.scratch_page =
-		    virt_to_phys((void *) agp_bridge.scratch_page);
-		agp_bridge.scratch_page =
-		    agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+		    agp_bridge.mask_memory(agp_bridge.scratch_page_real, 0);
 	}
 
 	size_value = agp_bridge.fetch_size();
@@ -5135,9 +5103,8 @@
 
 err_out:
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 	if (got_gatt)
 		agp_bridge.free_gatt_table();
@@ -5155,9 +5122,8 @@
 	vfree(agp_bridge.key_list);
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 }
 
diff -urN linux-2.4.21-pre1/drivers/char/drm/drm_auth.h linux-2.4.21-pre2/drivers/char/drm/drm_auth.h
--- linux-2.4.21-pre1/drivers/char/drm/drm_auth.h	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/char/drm/drm_auth.h	Wed Dec 18 14:16:27 2002
@@ -63,6 +63,7 @@
 	hash	     = DRM(hash_magic)(magic);
 	entry	     = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
 	if (!entry) return -ENOMEM;
+	memset(entry, 0, sizeof(*entry));
 	entry->magic = magic;
 	entry->priv  = priv;
 	entry->next  = NULL;
diff -urN linux-2.4.21-pre1/drivers/char/epca.c linux-2.4.21-pre2/drivers/char/epca.c
--- linux-2.4.21-pre1/drivers/char/epca.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/char/epca.c	Wed Dec 18 14:16:27 2002
@@ -2023,7 +2023,8 @@
 	    (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
 		shrinkmem = 1;
 	if (bd->type < PCIXEM)
-		request_region((int)bd->port, 4, board_desc[bd->type]);
+		if (!request_region((int)bd->port, 4, board_desc[bd->type]))
+			return;		
 
 	memwinon(bd, 0);
 
@@ -2187,9 +2188,13 @@
 		if (!(ch->tmp_buf))
 		{
 			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
-
+			release_region((int)bd->port, 4);
+			while(i-- > 0)
+				kfree((ch--)->tmp_buf);
+			return;
 		}
-		memset((void *)ch->tmp_buf,0,ch->txbufsize);
+		else 
+			memset((void *)ch->tmp_buf,0,ch->txbufsize);
 	} /* End for each port */
 
 	printk(KERN_INFO 
diff -urN linux-2.4.21-pre1/drivers/char/isicom.c linux-2.4.21-pre2/drivers/char/isicom.c
--- linux-2.4.21-pre1/drivers/char/isicom.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/char/isicom.c	Wed Dec 18 14:16:27 2002
@@ -2016,7 +2016,7 @@
 	retval=misc_register(&isiloader_device);
 	if (retval<0) {
 		printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
-		return -EIO;
+		return retval;
 	}
 	
 	if (!isicom_init()) {
diff -urN linux-2.4.21-pre1/drivers/char/joystick/pcigame.c linux-2.4.21-pre2/drivers/char/joystick/pcigame.c
--- linux-2.4.21-pre1/drivers/char/joystick/pcigame.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/char/joystick/pcigame.c	Wed Dec 18 14:16:27 2002
@@ -195,7 +195,7 @@
 
 int __init pcigame_init(void)
 {
-	pci_module_init(&pcigame_driver);
+	pci_register_driver(&pcigame_driver);
 	/* Needed by other modules */
 	return 0;
 }
diff -urN linux-2.4.21-pre1/drivers/char/pcmcia/serial_cs.c linux-2.4.21-pre2/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.21-pre1/drivers/char/pcmcia/serial_cs.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre2/drivers/char/pcmcia/serial_cs.c	Wed Dec 18 14:16:27 2002
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.128 2001/10/18 12:18:35
+    serial_cs.c 1.138 2002/10/25 06:24:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -28,7 +28,7 @@
     and other provisions required by the GPL.  If you do not delete
     the provisions above, a recipient may use your version of this
     file under either the MPL or the GPL.
-    
+
 ======================================================================*/
 
 #include <linux/module.h>
@@ -69,14 +69,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Enable the speaker? */
-INT_MODULE_PARM(do_sound, 1);
+INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
+INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
 
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -95,6 +95,7 @@
     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
@@ -148,7 +149,7 @@
     client_reg_t client_reg;
     dev_link_t *link;
     int i, ret;
-    
+
     DEBUG(0, "serial_attach()\n");
 
     /* Create new serial device */
@@ -160,7 +161,7 @@
     link->release.function = &serial_release;
     link->release.data = (u_long)link;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts1 = 8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
     if (irq_list[0] == -1)
@@ -169,13 +170,12 @@
 	for (i = 0; i < 4; i++)
 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     if (do_sound) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
 	link->conf.Status = CCSR_AUDIO_ENA;
     }
     link->conf.IntType = INT_MEMORY_AND_IO;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -194,7 +194,7 @@
 	serial_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* serial_attach */
 
@@ -214,7 +214,7 @@
     int ret;
 
     DEBUG(0, "serial_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
@@ -224,17 +224,17 @@
     del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	serial_release((u_long)link);
-    
+
     if (link->handle) {
 	ret = CardServices(DeregisterClient, link->handle);
 	if (ret != CS_SUCCESS)
 	    cs_error(link->handle, DeregisterClient, ret);
     }
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     kfree(info);
-    
+
 } /* serial_detach */
 
 /*====================================================================*/
@@ -243,18 +243,20 @@
 {
     struct serial_struct serial;
     int line;
-    
+
     memset(&serial, 0, sizeof(serial));
     serial.port = port;
     serial.irq = irq;
     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+    if (buggy_uart)
+	serial.flags |= ASYNC_BUGGY_UART;
     line = register_serial(&serial);
     if (line < 0) {
 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
 	return -1;
     }
-    
+
     info->line[info->ndev] = line;
     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
     info->node[info->ndev].major = TTY_MAJOR;
@@ -262,7 +264,7 @@
     if (info->ndev > 0)
 	info->node[info->ndev-1].next = &info->node[info->ndev];
     info->ndev++;
-    
+
     return 0;
 }
 
@@ -313,7 +315,10 @@
 	    return setup_serial(info, port, config.AssignedIRQ);
     }
     link->conf.Vcc = config.Vcc;
-    
+
+    link->io.NumPorts1 = 8;
+    link->io.NumPorts2 = 0;
+
     /* First pass: look for a config entry that looks normal. */
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
@@ -340,7 +345,7 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     /* Second pass: try to find an entry that isn't picky about
        its base address, then try to grab any standard serial port
        address, and finally try to get any free port. */
@@ -352,8 +357,7 @@
 	    for (j = 0; j < 5; j++) {
 		link->io.BasePort1 = base[j];
 		link->io.IOAddrLines = base[j] ? 16 : 3;
-		i = CardServices(RequestIO, link->handle,
-				 &link->io);
+		i = CardServices(RequestIO, link->handle, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
 	}
@@ -365,7 +369,7 @@
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -390,8 +394,12 @@
     u_char buf[256];
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    config_info_t config;
     int i, base2 = 0;
 
+    CardServices(GetConfigurationInfo, handle, &config);
+    link->conf.Vcc = config.Vcc;
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -433,12 +441,12 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
-	return -1;
+	/* At worst, try to configure as a single port */
+	return simple_config(link);
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -454,14 +462,27 @@
 	cs_error(link->handle, RequestConfiguration, i);
 	return -1;
     }
-    
+
+    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+       8 registers are for the UART, the others are extra registers */
+    if (info->manfid == MANFID_OXSEMI) {
+	if (cf->index == 1 || cf->index == 3) {
+	    setup_serial(info, base2, link->irq.AssignedIRQ);
+	    outb(12,link->io.BasePort1+1);
+	} else {
+	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	    outb(12,base2+1);
+	}
+	return 0;
+    }
+
     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
     /* The Nokia cards are not really multiport cards */
     if (info->manfid == MANFID_NOKIA)
 	return 0;
     for (i = 0; i < info->multi-1; i++)
 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-    
+
     return 0;
 }
 
@@ -487,7 +508,7 @@
     int i, last_ret, last_fn;
 
     DEBUG(0, "serial_config(0x%p)\n", link);
-    
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -500,7 +521,7 @@
     }
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -508,8 +529,8 @@
     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-    
-    /* Is this a multiport card? */
+
+    /* Scan list of known multiport card ID's */
     tuple.DesiredTuple = CISTPL_MANFID;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	info->manfid = le16_to_cpu(buf[0]);
@@ -537,15 +558,15 @@
 		info->multi = 2;
 	}
     }
-    
+
     if (info->multi > 1)
 	multi_config(link);
     else
 	simple_config(link);
-    
+
     if (info->ndev == 0)
 	goto failed;
-    
+
     if (info->manfid == MANFID_IBM) {
 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
@@ -562,6 +583,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     serial_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* serial_config */
 
@@ -569,7 +591,7 @@
 
     After a card is removed, serial_release() will unregister the net
     device, and release the PCMCIA configuration.
-    
+
 ======================================================================*/
 
 void serial_release(u_long arg)
@@ -577,7 +599,7 @@
     dev_link_t *link = (dev_link_t *)arg;
     serial_info_t *info = link->priv;
     int i;
-    
+
     DEBUG(0, "serial_release(0x%p)\n", link);
 
     for (i = 0; i < info->ndev; i++) {
@@ -590,7 +612,7 @@
 	CardServices(ReleaseIO, link->handle, &link->io);
 	CardServices(ReleaseIRQ, link->handle, &link->irq);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* serial_release */
@@ -601,7 +623,7 @@
     stuff to run after an event is received.  A CARD_REMOVAL event
     also sets some flags to discourage the serial drivers from
     talking to the ports.
-    
+
 ======================================================================*/
 
 static int serial_event(event_t event, int priority,
@@ -609,9 +631,9 @@
 {
     dev_link_t *link = args->client_data;
     serial_info_t *info = link->priv;
-    
+
     DEBUG(1, "serial_event(0x%06x)\n", event);
-    
+
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
@@ -650,7 +672,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "serial_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
     return 0;
diff -urN linux-2.4.21-pre1/drivers/char/serial.c linux-2.4.21-pre2/drivers/char/serial.c
--- linux-2.4.21-pre1/drivers/char/serial.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/char/serial.c	Wed Dec 18 14:16:27 2002
@@ -842,10 +842,15 @@
 		if (status & UART_LSR_DR)
 			receive_chars(info, &status, regs);
 		check_modem_status(info);
+#ifdef CONFIG_MELAN
 		if ((status & UART_LSR_THRE) ||
 			/* for buggy ELAN processors */
 			((iir & UART_IIR_ID) == UART_IIR_THRI))
 			transmit_chars(info, 0);
+#else
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#endif
 
 	next:
 		info = info->next_port;
diff -urN linux-2.4.21-pre1/drivers/char/tipar.c linux-2.4.21-pre2/drivers/char/tipar.c
--- linux-2.4.21-pre1/drivers/char/tipar.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/char/tipar.c	Wed Dec 18 14:16:27 2002
@@ -0,0 +1,538 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar - low level driver for handling a parallel link cable designed
+ * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Various fixes & clean-up from the Linux Kernel Mailing List
+ * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
+ */
+
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport
+ * abstraction layer.
+ *
+ * If this driver is built into the kernel, you can configure it using the
+ * kernel command-line.  For example:
+ *
+ *      tipar=timeout,delay       (set timeout and delay)
+ *
+ * If the driver is loaded as a module, similar functionality is available
+ * using module parameters.  The equivalent of the above commands would be:
+ *
+ *      # insmod tipar timeout=15 delay=10
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Usually, parallel cables were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ *      tipar0             0x378
+ *      tipar1             0x278
+ *      tipar2             0x3bc
+ *
+ *
+ * This driver, by default, binds tipar devices according to parport and
+ * the minor number.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <linux/devfs_fs_kernel.h>	/* DevFs support */
+#include <linux/parport.h>	/* Our code depend on parport */
+
+/*
+ * TI definitions
+ */
+#include <linux/ticable.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.18"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
+#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
+#define DRIVER_LICENSE "GPL"
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if LINUX_VERSION_CODE < VERSION(2,5,0)
+# define minor(x) MINOR(x)
+# define need_resched() (current->need_resched)
+#endif
+
+/* ----- global variables --------------------------------------------- */
+
+struct tipar_struct {
+	struct pardevice *dev;	/* Parport device entry */
+};
+
+#define PP_NO 3
+static struct tipar_struct table[PP_NO];
+
+static int delay = IO_DELAY;	/* inter-bit delay in microseconds */
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+static unsigned int tp_count;	/* tipar count */
+static unsigned long opened;	/* opened devices */
+
+/* --- macros for parport access -------------------------------------- */
+
+#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
+#define r_str(x)        (parport_read_status(table[(x)].dev->port))
+#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
+#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
+
+/* --- setting states on the D-bus with the right timing: ------------- */
+
+static inline void
+outbyte(int value, int minor)
+{
+	w_dtr(minor, value);
+}
+
+static inline int
+inbyte(int minor)
+{
+	return (r_str(minor));
+}
+
+static inline void
+init_ti_parallel(int minor)
+{
+	outbyte(3, minor);
+}
+
+/* ----- global defines ----------------------------------------------- */
+
+#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define WAIT(x)  { \
+  if (time_before((x), jiffies)) return -1; \
+  if (need_resched()) schedule(); }
+
+/* ----- D-bus bit-banging functions ---------------------------------- */
+
+/* D-bus protocol (45kbit/s max):
+                    1                 0                      0
+       _______        ______|______    __________|________    __________
+Red  :        ________      |      ____          |        ____
+       _        ____________|________      ______|__________       _____
+White:  ________            |        ______      |          _______
+*/
+
+/* Try to transmit a byte on the specified port (-1 if error). */
+static int
+put_ti_parallel(int minor, unsigned char data)
+{
+	int bit;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		if (data & 1) {
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x10);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+		} else {
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x20);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+		}
+
+		data >>= 1;
+		udelay(delay);
+
+		if (need_resched())
+			schedule();
+	}
+
+	return 0;
+}
+
+/* Receive a byte on the specified port or -1 if error. */
+static int
+get_ti_parallel(int minor)
+{
+	int bit;
+	unsigned char v, data = 0;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		START(max);
+		do {
+			WAIT(max);
+		} while ((v = inbyte(minor) & 0x30) == 0x30);
+
+		if (v == 0x10) {
+			data = (data >> 1) | 0x80;
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+			outbyte(3, minor);
+		} else {
+			data = data >> 1;
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+			outbyte(3, minor);
+		}
+
+		udelay(delay);
+		if (need_resched())
+			schedule();
+	}
+
+	return (int) data;
+}
+
+/* Try to detect a parallel link cable on the specified port */
+static int
+probe_ti_parallel(int minor)
+{
+	int i;
+	int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+
+	for (i = 3; i >= 0; i--) {
+		outbyte(3, minor);
+		outbyte(i, minor);
+		udelay(delay);
+		/*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
+		if ((inbyte(minor) & 0x30) != seq[i]) {
+			outbyte(3, minor);
+			return -1;
+		}
+	}
+
+	outbyte(3, minor);
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int
+tipar_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	if (test_and_set_bit(minor, &opened))
+		return -EBUSY;
+
+	parport_claim_or_block(table[minor].dev);
+	init_ti_parallel(minor);
+	parport_release(table[minor].dev);
+
+	return 0;
+}
+
+static int
+tipar_close(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	clear_bit(minor, &opened);
+
+	return 0;
+}
+
+static ssize_t
+tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t n;
+
+	parport_claim_or_block(table[minor].dev);
+
+	for (n = 0; n < count; n++) {
+		unsigned char b;
+
+		if (get_user(b, buf + n)) {
+			n = -EFAULT;
+			goto out;
+		}
+
+		if (put_ti_parallel(minor, b) == -1) {
+			init_ti_parallel(minor);
+			n = -ETIMEDOUT;
+			goto out;
+		}
+	}
+      out:
+	parport_release(table[minor].dev);
+	return n;
+}
+
+static ssize_t
+tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	int b = 0;
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t retval = 0;
+	ssize_t n = 0;
+
+	if (count == 0)
+		return 0;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	parport_claim_or_block(table[minor].dev);
+
+	while (n < count) {
+		b = get_ti_parallel(minor);
+		if (b == -1) {
+			init_ti_parallel(minor);
+			retval = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (put_user(b, ((unsigned char *) buf) + n)) {
+				retval = -EFAULT;
+				break;
+			} else
+				retval = ++n;
+		}
+
+		/* Non-blocking mode : try again ! */
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		/* Signal pending, try again ! */
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		if (need_resched())
+			schedule();
+	}
+
+      out:
+	parport_release(table[minor].dev);
+	return retval;
+}
+
+static int
+tipar_ioctl(struct inode *inode, struct file *file,
+	    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case IOCTL_TIPAR_DELAY:
+	  delay = (int)arg;    //get_user(delay, &arg);
+	  break;
+	case IOCTL_TIPAR_TIMEOUT:
+	  timeout = (int)arg;  //get_user(timeout, &arg);
+	  break;
+	default:
+		retval = -ENOTTY;
+		break;
+	}
+
+	return retval;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tipar_fops = {
+	owner:THIS_MODULE,
+	llseek:no_llseek,
+	read:tipar_read,
+	write:tipar_write,
+	ioctl:tipar_ioctl,
+	open:tipar_open,
+	release:tipar_close,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init
+tipar_setup(char *str)
+{
+	int ints[2];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+		if (ints[0] > 1) {
+			delay = ints[2];
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * Register our module into parport.
+ * Pass also 2 callbacks functions to parport: a pre-emptive function and an
+ * interrupt handler function (unused).
+ * Display a message such "tipar0: using parport0 (polling)".
+ */
+static int
+tipar_register(int nr, struct parport *port)
+{
+	char name[8];
+
+	/* Register our module into parport */
+	table[nr].dev = parport_register_device(port, "tipar",
+						NULL, NULL, NULL, 0,
+						(void *) &table[nr]);
+
+	if (table[nr].dev == NULL)
+		return 1;
+
+	/* Use devfs, tree: /dev/ticables/par/[0..2] */
+	sprintf(name, "%d", nr);
+	printk
+	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
+	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
+	devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
+		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
+		       &tipar_fops, NULL);
+
+	/* Display informations */
+	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
+	       (port->irq ==
+		PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
+
+	if (probe_ti_parallel(nr) != -1)
+		printk("tipar%d: link cable found !\n", nr);
+	else
+		printk("tipar%d: link cable not found.\n", nr);
+
+	return 0;
+}
+
+static void
+tipar_attach(struct parport *port)
+{
+	if (tp_count == PP_NO) {
+		printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
+		return;
+	}
+
+	if (!tipar_register(tp_count, port))
+		tp_count++;
+}
+
+static void
+tipar_detach(struct parport *port)
+{
+	/* Nothing to do */
+}
+
+static struct parport_driver tipar_driver = {
+	"tipar",
+	tipar_attach,
+	tipar_detach,
+	NULL
+};
+
+int __init
+tipar_init_module(void)
+{
+	printk("tipar: parallel link cable driver, version %s\n",
+	       DRIVER_VERSION);
+
+	if (devfs_register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
+		printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs with tree: /dev/ticables/par/[0..2] */
+	devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
+
+	if (parport_register_driver(&tipar_driver)) {
+		printk("tipar: unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void __exit
+tipar_cleanup_module(void)
+{
+	unsigned int i;
+
+	/* Unregistering module */
+	parport_unregister_driver(&tipar_driver);
+
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(TIPAR_MAJOR, "tipar");
+
+	for (i = 0; i < PP_NO; i++) {
+		if (table[i].dev == NULL)
+			continue;
+		parport_unregister_device(table[i].dev);
+	}
+
+	printk("tipar: module unloaded !\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup("tipar=", tipar_setup);
+module_init(tipar_init_module);
+module_exit(tipar_cleanup_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM(delay, "i");
+MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");
diff -urN linux-2.4.21-pre1/drivers/char/wdt285.c linux-2.4.21-pre2/drivers/char/wdt285.c
--- linux-2.4.21-pre1/drivers/char/wdt285.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.21-pre2/drivers/char/wdt285.c	Wed Dec 18 14:16:27 2002
@@ -179,10 +179,15 @@
 
 static int __init footbridge_watchdog_init(void)
 {
+	int retval;
+
 	if (machine_is_netwinder())
 		return -ENODEV;
 
-	misc_register(&watchdog_miscdev);
+	retval = misc_register(&watchdog_miscdev);
+	if(retval < 0)
+		return retval;
+
 	printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", 
 	       soft_margin);
 	if (machine_is_cats())
diff -urN linux-2.4.21-pre1/drivers/gsc/dino.c linux-2.4.21-pre2/drivers/gsc/dino.c
--- linux-2.4.21-pre1/drivers/gsc/dino.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/gsc/dino.c	Wed Dec 18 14:16:27 2002
@@ -436,7 +436,7 @@
 	if (mask) {
 		if (--ilr_loop > 0)
 			goto ilr_again;
-		printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
+		printk("Dino %lx: IRQ base %d, stuck IRQ lines? 0x%x\n", dino_dev->hba.base_addr, dino_dev->dino_region->data.irqbase, mask);
 	}
 }
 
diff -urN linux-2.4.21-pre1/drivers/gsc/lasi.c linux-2.4.21-pre2/drivers/gsc/lasi.c
--- linux-2.4.21-pre1/drivers/gsc/lasi.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/gsc/lasi.c	Wed Dec 18 14:16:27 2002
@@ -26,7 +26,7 @@
 #include <asm/gsc.h>
 #include <asm/hardware.h>
 #include <asm/led.h>
-
+#include <asm/pdc.h>
 #include "busdevice.h"
 
 
@@ -77,7 +77,10 @@
 
 	/* Resets */
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
-	gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
+	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
+		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
 	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
diff -urN linux-2.4.21-pre1/drivers/hil/hil_kbd.c linux-2.4.21-pre2/drivers/hil/hil_kbd.c
--- linux-2.4.21-pre1/drivers/hil/hil_kbd.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/hil/hil_kbd.c	Wed Dec 18 14:16:27 2002
@@ -431,9 +431,9 @@
 
 
 struct serio_dev hil_kbd_serio_dev = {
-	connect:	hil_kbd_connect,
-	disconnect:	hil_kbd_disconnect,
-	interrupt:	hil_kbd_interrupt
+	.connect =	hil_kbd_connect,
+	.disconnect =	hil_kbd_disconnect,
+	.interrupt =	hil_kbd_interrupt
 };
 
 static int __init hil_kbd_init(void)
diff -urN linux-2.4.21-pre1/drivers/hil/hil_ptr.c linux-2.4.21-pre2/drivers/hil/hil_ptr.c
--- linux-2.4.21-pre1/drivers/hil/hil_ptr.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/hil/hil_ptr.c	Wed Dec 18 14:16:27 2002
@@ -386,9 +386,9 @@
 
 
 struct serio_dev hil_ptr_serio_dev = {
-	connect: hil_ptr_connect,
-	disconnect: hil_ptr_disconnect,
-	interrupt: hil_ptr_interrupt
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
 };
 
 static int __init hil_ptr_init(void)
diff -urN linux-2.4.21-pre1/drivers/hil/hilkbd.c linux-2.4.21-pre2/drivers/hil/hilkbd.c
--- linux-2.4.21-pre1/drivers/hil/hilkbd.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/hil/hilkbd.c	Wed Dec 18 14:16:27 2002
@@ -348,9 +348,9 @@
 MODULE_DEVICE_TABLE(parisc, hil_tbl);
 
 static struct parisc_driver hil_driver = {
-	name:		"HIL",
-	id_table:	hil_tbl,
-	probe:		hil_init_chip,
+	.name =		"HIL",
+	.id_table =	hil_tbl,
+	.probe =	hil_init_chip,
 };
 #endif /* CONFIG_PARISC */
 
diff -urN linux-2.4.21-pre1/drivers/hil/hp_sdc.c linux-2.4.21-pre2/drivers/hil/hp_sdc.c
--- linux-2.4.21-pre1/drivers/hil/hp_sdc.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/hil/hp_sdc.c	Wed Dec 18 14:16:27 2002
@@ -745,10 +745,10 @@
 
 static struct parisc_device_id hp_sdc_tbl[] = {
 	{
-		hw_type:	HPHW_FIO, 
-		hversion_rev:	HVERSION_REV_ANY_ID,
-		hversion:	HVERSION_ANY_ID,
-		sversion:	0x73, 
+		.hw_type =	HPHW_FIO, 
+		.hversion_rev =	HVERSION_REV_ANY_ID,
+		.hversion =	HVERSION_ANY_ID,
+		.sversion =	0x73, 
 	 },
 	{ 0, }
 };
@@ -758,9 +758,9 @@
 static int __init hp_sdc_init(struct parisc_device *d);
 
 static struct parisc_driver hp_sdc_driver = {
-	name:		"HP SDC",
-	id_table:	hp_sdc_tbl,
-	probe:		hp_sdc_init,
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init,
 };
 
 static int __init hp_sdc_init(struct parisc_device *d)
diff -urN linux-2.4.21-pre1/drivers/hil/hp_sdc_rtc.c linux-2.4.21-pre2/drivers/hil/hp_sdc_rtc.c
--- linux-2.4.21-pre1/drivers/hil/hp_sdc_rtc.c	Thu Nov 28 15:53:12 2002
+++ linux-2.4.21-pre2/drivers/hil/hp_sdc_rtc.c	Wed Dec 18 14:16:27 2002
@@ -674,20 +674,20 @@
 }
 
 static struct file_operations hp_sdc_rtc_fops = {
-        owner:          THIS_MODULE,
-        llseek:         hp_sdc_rtc_llseek,
-        read:           hp_sdc_rtc_read,
-        poll:           hp_sdc_rtc_poll,
-        ioctl:          hp_sdc_rtc_ioctl,
-        open:           hp_sdc_rtc_open,
-        release:        hp_sdc_rtc_release,
-        fasync:         hp_sdc_rtc_fasync,
+        .owner =	THIS_MODULE,
+        .llseek =	hp_sdc_rtc_llseek,
+        .read =		hp_sdc_rtc_read,
+        .poll =		hp_sdc_rtc_poll,
+        .ioctl =	hp_sdc_rtc_ioctl,
+        .open =		hp_sdc_rtc_open,
+        .release =	hp_sdc_rtc_release,
+        .fasync =	hp_sdc_rtc_fasync,
 };
 
 static struct miscdevice hp_sdc_rtc_dev = {
-        minor:		RTC_MINOR,
-        name:		"rtc",
-        fops:		&hp_sdc_rtc_fops
+        .minor =	RTC_MINOR,
+        .name =		"rtc",
+        .fops =		&hp_sdc_rtc_fops
 };
 
 static int __init hp_sdc_rtc_init(void)
diff -urN linux-2.4.21-pre1/drivers/hotplug/acpiphp.h linux-2.4.21-pre2/drivers/hotplug/acpiphp.h
--- linux-2.4.21-pre1/drivers/hotplug/acpiphp.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/hotplug/acpiphp.h	Wed Dec 18 14:16:27 2002
@@ -173,8 +173,6 @@
 	/* PCI-to-PCI bridge device */
 	struct pci_dev *pci_dev;
 
-	struct pci_ops *pci_ops;
-
 	/* ACPI 2.0 _HPP parameters */
 	struct hpp_param hpp;
 
diff -urN linux-2.4.21-pre1/drivers/hotplug/acpiphp_glue.c linux-2.4.21-pre2/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.21-pre1/drivers/hotplug/acpiphp_glue.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/hotplug/acpiphp_glue.c	Wed Dec 18 14:16:27 2002
@@ -43,7 +43,6 @@
 
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void handle_hotplug_event_func (acpi_handle, u32, void *);
-static struct pci_ops *default_ops;
 
 /*
  * initialization & terminatation routines
@@ -515,7 +514,6 @@
 	bridge->bus = bus;
 
 	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -592,7 +590,6 @@
 		kfree(bridge);
 		return;
 	}
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -1072,11 +1069,9 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			pci_read_config_dword_nodev(default_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
-						    PCI_VENDOR_ID, &dvid);
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, func->function),
+					PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				sta = ACPI_STA_ALL;
 				break;
@@ -1206,11 +1201,6 @@
 	if (list_empty(&pci_root_buses))
 		return -1;
 
-	/* set default pci_ops for configuration space operation */
-	default_ops = pci_bus_b(pci_root_buses.next)->ops;
-	if (!default_ops)
-		return -1;
-
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 				     ACPI_UINT32_MAX, find_host_bridge,
 				     NULL, NULL);
diff -urN linux-2.4.21-pre1/drivers/hotplug/acpiphp_pci.c linux-2.4.21-pre2/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.21-pre1/drivers/hotplug/acpiphp_pci.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/hotplug/acpiphp_pci.c	Wed Dec 18 14:16:27 2002
@@ -58,23 +58,22 @@
 	int count;
 	struct acpiphp_bridge *bridge;
 	struct pci_resource *res;
-	struct pci_ops *ops;
-	int bus, device, function;
+	struct pci_bus *bus;
+	int devfn;
 
 	bridge = func->slot->bridge;
-	bus = bridge->bus;
-	device = func->slot->device;
-	function = func->function;
-	ops = bridge->pci_ops;
+	bus = bridge->pci_bus;
+	devfn = PCI_DEVFN(func->slot->device, func->function);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_write_config_dword_nodev(ops, bus, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+		pci_bus_write_config_dword(bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword(bus, devfn, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
+		dbg("Device %02x.%d BAR %d wants %x\n", PCI_SLOT(devfn),
+				PCI_FUNC(devfn), count, bar);
 
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -90,10 +89,10 @@
 
 			if (!res) {
 				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
-				    bus, device, function, len);
+				    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 				return -1;
 			}
-			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 			res->next = func->io_head;
 			func->io_head = res;
 
@@ -113,16 +112,16 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
 					dbg("inside the pfmem 64 case, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->p_mem_head;
@@ -142,17 +141,17 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
 					dbg("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->mem_head;
@@ -163,7 +162,7 @@
 	}
 
 	/* disable expansion rom */
-	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+	pci_bus_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, 0x00000000);
 
 	return 0;
 }
@@ -556,9 +555,9 @@
 	int retval = 0;
 	int is_multi = 0;
 
-	pci_read_config_byte_nodev(slot->bridge->pci_ops,
-				   slot->bridge->bus, slot->device, 0,
-				   PCI_HEADER_TYPE, &hdr);
+	pci_bus_read_config_byte(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, 0),
+					PCI_HEADER_TYPE, &hdr);
 
 	if (hdr & 0x80)
 		is_multi = 1;
@@ -566,10 +565,9 @@
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 		if (is_multi || func->function == 0) {
-			pci_read_config_dword_nodev(slot->bridge->pci_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						    PCI_DEVFN(slot->device,
+								func->function),
 						    PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				retval = init_config_space(func);
diff -urN linux-2.4.21-pre1/drivers/hotplug/pci_hotplug.h linux-2.4.21-pre2/drivers/hotplug/pci_hotplug.h
--- linux-2.4.21-pre1/drivers/hotplug/pci_hotplug.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/hotplug/pci_hotplug.h	Wed Dec 18 14:16:27 2002
@@ -167,6 +167,18 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+
+/*
+ * Compatibility functions.  Don't use these, use the
+ * pci_bus_*() functions above.
+ */
+
 extern int pci_read_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
 					 u8 function, int where, u8 *val);
 extern int pci_read_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
diff -urN linux-2.4.21-pre1/drivers/hotplug/pci_hotplug_util.c linux-2.4.21-pre2/drivers/hotplug/pci_hotplug_util.c
--- linux-2.4.21-pre1/drivers/hotplug/pci_hotplug_util.c	Fri Nov  9 14:01:22 2001
+++ linux-2.4.21-pre2/drivers/hotplug/pci_hotplug_util.c	Wed Dec 18 14:16:27 2002
@@ -50,78 +50,58 @@
 /* local variables */
 static int debug;
 
-
-static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev)
+static int build_dev (struct pci_bus *bus, unsigned int devfn, struct pci_dev **pci_dev)
 {
 	struct pci_dev *my_dev;
-	struct pci_bus *my_bus;
-
-	/* Some validity checks. */
-	if ((function > 7) ||
-	    (slot > 31) ||
-	    (pci_dev == NULL) ||
-	    (ops == NULL))
-		return -ENODEV;
 
 	my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL);
 	if (!my_dev)
 		return -ENOMEM;
-	my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL);
-	if (!my_bus) {
-		kfree (my_dev);
-		return -ENOMEM;
-	}
+
 	memset(my_dev, 0, sizeof(struct pci_dev));
-	memset(my_bus, 0, sizeof(struct pci_bus));
 
-	my_bus->number = bus;
-	my_bus->ops = ops;
-	my_dev->devfn = PCI_DEVFN(slot, function);
-	my_dev->bus = my_bus;
+	my_dev->devfn = devfn;
+	my_dev->bus = bus;
+	my_dev->sysdata = bus->sysdata;
 	*pci_dev = my_dev;
 	return 0;
 }
 
 /**
- * pci_read_config_byte_nodev - read a byte from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
- * @where: the location on the pci address space to read from
+ * pci_bus_read_config_byte - read a byte from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
+ * @where: the location in the pci address space to read from
  * @value: pointer to where to place the data read
  *
  * Like pci_read_config_byte() but works for pci devices that do not have a
  * pci_dev structure set up yet.
  * Returns 0 on success.
  */
-int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value)
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_word_nodev - read a word from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_word - read a word from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -129,34 +109,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value)
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_dword_nodev - read a dword from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci
- * device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_dword - read a dword from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -164,34 +140,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value)
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_byte_nodev - write a byte to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_byte - write a byte to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -199,34 +171,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value)
+int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_word_nodev - write a word to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_word - write a word to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -234,34 +202,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value)
+int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_dword_nodev - write a dword to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_dword - write a dword to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -269,23 +233,22 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value)
+int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
@@ -392,8 +355,98 @@
 	return result;
 }
 
+/* Compatibility wrapper functions */
+
+static struct pci_bus *alloc_bus(struct pci_ops *ops, u8 bus_nr)
+{
+	struct pci_bus *bus = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+	memset(bus, 0, sizeof(struct pci_bus));
+	bus->number = bus_nr;
+	bus->ops = ops;
+	return bus;
+}
+
+int pci_read_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
 
 EXPORT_SYMBOL(pci_visit_dev);
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
 EXPORT_SYMBOL(pci_read_config_byte_nodev);
 EXPORT_SYMBOL(pci_read_config_word_nodev);
 EXPORT_SYMBOL(pci_read_config_dword_nodev);
diff -urN linux-2.4.21-pre1/drivers/i2c/Config.in linux-2.4.21-pre2/drivers/i2c/Config.in
--- linux-2.4.21-pre1/drivers/i2c/Config.in	Mon Feb 25 11:37:57 2002
+++ linux-2.4.21-pre2/drivers/i2c/Config.in	Wed Dec 18 14:16:27 2002
@@ -13,6 +13,12 @@
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
       dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
       dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+      dep_tristate '  NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT
+      if [ "$CONFIG_SCx200_I2C" != "n" ]; then
+         int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+         int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+      fi
+      dep_tristate '  NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
    fi
 
    dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
diff -urN linux-2.4.21-pre1/drivers/i2c/Makefile linux-2.4.21-pre2/drivers/i2c/Makefile
--- linux-2.4.21-pre1/drivers/i2c/Makefile	Mon Feb 25 11:37:57 2002
+++ linux-2.4.21-pre2/drivers/i2c/Makefile	Wed Dec 18 14:16:27 2002
@@ -18,6 +18,8 @@
 obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 
 # This is needed for automatic patch generation: sensors code starts here
diff -urN linux-2.4.21-pre1/drivers/i2c/scx200_acb.c linux-2.4.21-pre2/drivers/i2c/scx200_acb.c
--- linux-2.4.21-pre1/drivers/i2c/scx200_acb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/i2c/scx200_acb.c	Wed Dec 18 14:16:27 2002
@@ -0,0 +1,579 @@
+/*  linux/drivers/i2c/scx200_acb.c 
+
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+   
+    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.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+   implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct semaphore sem;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20 
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define	   ACBCTL1_ACK		0x10
+#define	   ACBCTL1_STOP		0x02
+#define	   ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	DBG("state %s, status = 0x%02x\n", 
+	    scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK)
+		goto negack;
+
+	switch (iface->state) {
+	case state_idle:
+		printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", 
+		       iface->adapter.name);
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+		
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1) 
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if receiving the last byte */
+		if (iface->len == 1)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+		
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+		
+		break;
+	}
+
+	return;
+
+ negack:
+	DBG("negative acknowledge in state %s\n", 
+	    scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -ENXIO;
+
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+	return;
+
+ error:
+	printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, 
+	       errmsg, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
+{
+	printk(KERN_ERR NAME ": %s, timeout in state %s\n", 
+	       iface->adapter.name, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status = 0;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (time_before(jiffies, timeout)) {
+		status = inb(ACBST);
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		yield();
+	}
+
+	scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				u16 address, unsigned short flags,	
+				char rw, u8 command, int size, 
+				union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = adapter->data;
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+	    	len = 0;
+	    	buffer = NULL;
+	    	break;
+	case I2C_SMBUS_BYTE:
+		if (rw == I2C_SMBUS_READ) {
+			len = 1;
+			buffer = &data->byte;
+		} else {
+			len = 1;
+			buffer = &command;
+		}
+	    	break;
+	case I2C_SMBUS_BYTE_DATA:
+	    	len = 1;
+	    	buffer = &data->byte;
+	    	break;
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+	    	cur_word = cpu_to_le16(data->word);
+	    	buffer = (u8 *)&cur_word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	    	len = data->block[0];
+	    	buffer = &data->block[1];
+		break;
+	default:
+	    	return -EINVAL;
+	}
+
+	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+	    size, address, command, len, rw == I2C_SMBUS_READ);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		printk(KERN_WARNING NAME ": %s, zero length read\n", 
+		       adapter->name);
+		return -EINVAL;
+	}
+
+	if (len && !buffer) {
+		printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name);
+		return -EFAULT;
+	}
+
+	down(&iface->sem);
+
+	iface->address_byte = address<<1;
+	if (rw == I2C_SMBUS_READ)
+		iface->address_byte |= 1;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+#ifdef POLLED_MODE
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */	
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	up(&iface->sem);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+	    	data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+	printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int scx200_acb_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_acb_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_acb_inc_use(struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_acb_dec_use(struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+	name:		"NatSemi SCx200 ACCESS.bus",
+	id:		I2C_ALGO_SMBUS,
+	smbus_xfer:	scx200_acb_smbus_xfer,
+	functionality:	scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		DBG("ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int  __init scx200_acb_create(int base, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+	int rc = 0;
+	char description[64];
+
+	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		rc = -ENOMEM;
+		goto errout;
+	}
+
+	memset(iface, 0, sizeof(*iface));
+	adapter = &iface->adapter;
+	adapter->data = iface;
+	sprintf(adapter->name, "SCx200 ACB%d", index);
+	adapter->id = I2C_ALGO_SMBUS;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->inc_use = scx200_acb_inc_use;
+	adapter->dec_use = scx200_acb_dec_use;
+	adapter->client_register = scx200_acb_reg;
+	adapter->client_unregister = scx200_acb_unreg;
+
+	init_MUTEX(&iface->sem);
+
+	sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+	if (request_region(base, 8, description) == 0) {
+		printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", 
+		       adapter->name, base, base + 8-1);
+		rc = -EBUSY;
+		goto errout;
+	}
+	iface->base = base;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name);
+		goto errout;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name);
+		rc = -ENODEV;
+		goto errout;
+	}
+
+	lock_kernel();
+	iface->next = scx200_acb_list;
+	scx200_acb_list = iface;
+	unlock_kernel();
+
+	return 0;
+
+ errout:
+	if (iface) {
+		if (iface->base)
+			release_region(iface->base, 8);
+		kfree(iface);
+	}
+	return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+	int i;
+	int rc;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* Verify that this really is a SCx200 processor */
+	if (pci_find_device(PCI_VENDOR_ID_NS,
+			    PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			    NULL) == NULL)
+		return -ENODEV;
+
+	rc = -ENXIO;
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] > 0)
+			rc = scx200_acb_create(base[i], i);
+	}
+	if (scx200_acb_list)
+		return 0;
+	return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+	lock_kernel();
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		unlock_kernel();
+
+		i2c_del_adapter(&iface->adapter);
+		release_region(iface->base, 8);
+		kfree(iface);
+		lock_kernel();
+	}
+	unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
+
diff -urN linux-2.4.21-pre1/drivers/i2c/scx200_i2c.c linux-2.4.21-pre2/drivers/i2c/scx200_i2c.c
--- linux-2.4.21-pre1/drivers/i2c/scx200_i2c.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/i2c/scx200_i2c.c	Wed Dec 18 14:16:27 2002
@@ -0,0 +1,156 @@
+/* linux/drivers/i2c/scx200_i2c.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   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.		     
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+static int scx200_i2c_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_i2c_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_i2c_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_i2c_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	NULL,
+	scx200_i2c_setsda,
+	scx200_i2c_setscl,
+	scx200_i2c_getsda,
+	scx200_i2c_getscl,
+	10, 10, 100,		/* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.name              = "NatSemi SCx200 I2C",
+	.id		   = I2C_HW_B_VELLE,
+	.algo_data	   = &scx200_i2c_data,
+	.inc_use	   = scx200_i2c_inc_use,
+	.dec_use	   = scx200_i2c_dec_use,
+	.client_register   = scx200_i2c_reg,
+	.client_unregister = scx200_i2c_unreg,
+};
+
+int scx200_i2c_init(void)
+{
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", 
+	       scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+	i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff -urN linux-2.4.21-pre1/drivers/ide/Config.in linux-2.4.21-pre2/drivers/ide/Config.in
--- linux-2.4.21-pre1/drivers/ide/Config.in	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/Config.in	Wed Dec 18 14:16:27 2002
@@ -69,7 +69,7 @@
 		# FIXME - probably wants to be one for old and for new
 	    dep_bool     '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX_NEW
 	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-	    dep_tristate '    SCx200 chipsetsupport' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    SCx200 chipset support' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
diff -urN linux-2.4.21-pre1/drivers/ide/ide-iops.c linux-2.4.21-pre2/drivers/ide/ide-iops.c
--- linux-2.4.21-pre1/drivers/ide/ide-iops.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/ide-iops.c	Wed Dec 18 14:16:27 2002
@@ -32,52 +32,52 @@
 #include <asm/bitops.h>
 
 
-static u8 ide_inb (u32 port)
+static u8 ide_inb (unsigned long port)
 {
 	return (u8) inb(port);
 }
 
-static u16 ide_inw (u32 port)
+static u16 ide_inw (unsigned long port)
 {
 	return (u16) inw(port);
 }
 
-static void ide_insw (u32 port, void *addr, u32 count)
+static void ide_insw (unsigned long port, void *addr, u32 count)
 {
 	return insw(port, addr, count);
 }
 
-static u32 ide_inl (u32 port)
+static u32 ide_inl (unsigned long port)
 {
 	return (u32) inl(port);
 }
 
-static void ide_insl (u32 port, void *addr, u32 count)
+static void ide_insl (unsigned long port, void *addr, u32 count)
 {
 	insl(port, addr, count);
 }
 
-static void ide_outb (u8 addr, u32 port)
+static void ide_outb (u8 addr, unsigned long port)
 {
 	outb(addr, port);
 }
 
-static void ide_outw (u16 addr, u32 port)
+static void ide_outw (u16 addr, unsigned long port)
 {
 	outw(addr, port);
 }
 
-static void ide_outsw (u32 port, void *addr, u32 count)
+static void ide_outsw (unsigned long port, void *addr, u32 count)
 {
 	outsw(port, addr, count);
 }
 
-static void ide_outl (u32 addr, u32 port)
+static void ide_outl (u32 addr, unsigned long port)
 {
 	outl(addr, port);
 }
 
-static void ide_outsl (u32 port, void *addr, u32 count)
+static void ide_outsl (unsigned long port, void *addr, u32 count)
 {
 	return outsl(port, addr, count);
 }
@@ -98,73 +98,54 @@
 
 EXPORT_SYMBOL(default_hwif_iops);
 
-static u8 ide_mm_inb (u32 port)
+static u8 ide_mm_inb (unsigned long port)
 {
 	return (u8) readb(port);
 }
 
-static u16 ide_mm_inw (u32 port)
+static u16 ide_mm_inw (unsigned long port)
 {
 	return (u16) readw(port);
 }
 
-static void ide_mm_insw (u32 port, void *addr, u32 count)
+static void ide_mm_insw (unsigned long port, void *addr, u32 count)
 {
-#ifdef CONFIG_PPC
-	/* Can we move the barrier out of the loop ? */
-	while (count--) { *(u16 *)addr = __raw_readw(port); iobarrier_r(); addr += 2; }
-#else /* everything else is sane benh */
-	while (count--) { *(u16 *)addr = readw(port); addr += 2; }
-#endif
+	__ide_mm_insw(port, addr, count);
 }
 
-static u32 ide_mm_inl (u32 port)
+static u32 ide_mm_inl (unsigned long port)
 {
 	return (u32) readl(port);
 }
 
-static void ide_mm_insl (u32 port, void *addr, u32 count)
+static void ide_mm_insl (unsigned long port, void *addr, u32 count)
 {
-#ifdef CONFIG_PPC
-	/* Can we move the barrier out of the loop ? */
-	while (count--) { *(u32 *)addr = __raw_readl(port); iobarrier_r(); addr += 4; }
-#else /* everything else is sane benh */
-	while (count--) { *(u32 *)addr = readl(port); addr += 4; }
-#endif
+	__ide_mm_insl(port, addr, count);
 }
 
-static void ide_mm_outb (u8 value, u32 port)
+static void ide_mm_outb (u8 value, unsigned long port)
 {
 	writeb(value, port);
 }
 
-static void ide_mm_outw (u16 value, u32 port)
+static void ide_mm_outw (u16 value, unsigned long port)
 {
 	writew(value, port);
 }
 
-static void ide_mm_outsw (u32 port, void *addr, u32 count)
+static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
 {
-#ifdef CONFIG_PPC
-	/* Can we move the barrier out of the loop ? */
-	while (count--) { __raw_writew(*(u16 *)addr, port); iobarrier_w(); addr += 2; }
-#else /* everything else is sane benh */
-	while (count--) { writew(*(u16 *)addr, port); addr += 2; }
-#endif
+	__ide_mm_outsw(port, addr, count);
 }
 
-static void ide_mm_outl (u32 value, u32 port)
+static void ide_mm_outl (u32 value, unsigned long port)
 {
 	writel(value, port);
 }
 
-static void ide_mm_outsl (u32 port, void *addr, u32 count)
+static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
 {
-#ifdef CONFIG_PPC
-	while (count--) { __raw_writel(*(u32 *)addr, port); iobarrier_w(); addr += 4; }
-#else /* everything else is sane benh */
-	while (count--) { writel(*(u32 *)addr, port); addr += 4; }
-#endif
+	__ide_mm_outsl(port, addr, count);
 }
 
 void default_hwif_mmiops (ide_hwif_t *hwif)
diff -urN linux-2.4.21-pre1/drivers/ide/ide-tape.c linux-2.4.21-pre2/drivers/ide/ide-tape.c
--- linux-2.4.21-pre1/drivers/ide/ide-tape.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/ide-tape.c	Wed Dec 18 14:16:27 2002
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ * linux/drivers/ide/ide-tape.c		Version 1.17b	Dec, 2002
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- Limit size of pipeline
+ * Ver 1.17b Dec 2002   Alan Stern <stern@rowland.harvard.edu>
+ *			Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ *			 it in the code!
+ *			Actually removed aborted stages in idetape_abort_pipeline
+ *			 instead of just changing the command code.
+ *			Made the transfer byte count for Request Sense equal to the
+ *			 actual length of the data transfer.
+ *			Changed handling of partial data transfers: they do not
+ *			 cause DMA errors.
+ *			Moved initiation of DMA transfers to the correct place.
+ *			Removed reference to unallocated memory.
+ *			Made __idetape_discard_read_pipeline return the number of
+ *			 sectors skipped, not the number of stages.
+ *			Replaced errant kfree() calls with __idetape_kfree_stage().
+ *			Fixed off-by-one error in testing the pipeline length.
+ *			Fixed handling of filemarks in the read pipeline.
+ *			Small code optimization for MTBSF and MTBSFM ioctls.
+ *			Don't try to unlock the door during device close if is
+ *			 already unlocked!
+ *			Cosmetic fixes to miscellaneous debugging output messages.
+ *			Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ *			 "pipeline_min", and "pipeline_max" to 1.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.17a"
+#define IDETAPE_VERSION "1.17b"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -576,9 +598,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	the optimum value or until we reach MAX.
  *
- *	Setting the following parameter to 0 will disable the pipelined mode.
+ *	Setting the following parameter to 0 is illegal: the pipelined mode
+ *	cannot be disabled (calculate_speeds() divides by tape->max_stages.)
  */
-#define IDETAPE_MIN_PIPELINE_STAGES	200
+#define IDETAPE_MIN_PIPELINE_STAGES	  1
 #define IDETAPE_MAX_PIPELINE_STAGES	400
 #define IDETAPE_INCREASE_STAGES_RATE	 20
 
@@ -600,8 +623,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -1699,25 +1722,6 @@
 	}
 }
 
-static void idetape_abort_pipeline (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage = tape->next_stage;
-
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
-		printk(KERN_INFO "ide-tape: %s: %s called\n",
-			tape->name, __FUNCTION__);
-#endif
-	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1763,7 +1767,7 @@
 		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1839,6 +1843,30 @@
 	}
 }
 
+static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage = tape->next_stage;
+	idetape_stage_t *nstage;
+
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
+		printk(KERN_INFO "ide-tape: %s: %s called\n",
+			tape->name, __FUNCTION__);
+#endif
+	while (stage) {
+		nstage = stage->next;
+		idetape_kfree_stage(tape, stage);
+		--tape->nr_stages;
+		--tape->nr_pending_stages;
+		stage = nstage;
+	}
+	tape->last_stage = last_stage;
+	if (last_stage)
+		last_stage->next = NULL;
+	tape->next_stage = NULL;
+}
+
 /*
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
@@ -1850,6 +1878,7 @@
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1873,6 +1902,7 @@
 	spin_lock_irqsave(&tape->spinlock, flags);
 	if (tape->active_data_request == rq) {
 		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1892,18 +1922,20 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					if (tape->debug_level >= 2)
-						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
+						printk("ide-tape: %s: skipping over config partition.\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline(drive);
+					idetape_abort_pipeline(drive, active_stage);
 				if (tape->onstream && !tape->raw &&
 				    error == IDETAPE_ERROR_GENERAL &&
 				    tape->sense.sense_key == 3) {
@@ -1914,14 +1946,16 @@
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
-				idetape_abort_pipeline(drive);
+				idetape_abort_pipeline(drive, active_stage);
 			}
 		}
 		if (tape->next_stage != NULL && !tape->onstream_write_error) {
@@ -1969,7 +2003,7 @@
 	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -2071,7 +2105,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->ide_dma_end(drive)) {
+		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2083,8 +2117,18 @@
 			 * actually transferred (we can't receive that
 			 * information from the DMA engine on most chipsets).
 			 */
+
+			/*
+			 * On the contrary, a DMA error is never expected;
+			 * it usually indicates a hardware error or abort.
+			 * If the tape crosses a filemark during a READ
+			 * command, it will issue an irq and position itself
+			 * after the filemark (not before). Only a partial
+			 * data transfer will occur, but no DMA error.
+			 * (AS, 19 Apr 2001)
+			 */
 			set_bit (PC_DMA_ERROR, &pc->flags);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2123,7 +2167,7 @@
 			/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: %s: I/O error, ",
+				printk(KERN_INFO "ide-tape: %s: I/O error\n",
 					tape->name);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2314,6 +2358,11 @@
 		BUG();
 	/* Set the interrupt routine */
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	/* Begin DMA, if necessary */
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+#endif
 	/* Send the actual packet */
 	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
@@ -2343,8 +2392,7 @@
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
 			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
@@ -2371,7 +2419,8 @@
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+		printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n",
+				pc->retries, pc->c[0]);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
@@ -2404,10 +2453,8 @@
 	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
 	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (feature.b.dma) {		/* Begin DMA, if necessary */
+	if (feature.b.dma)		/* Will begin DMA later */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
-	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		if (HWGROUP(drive)->handler != NULL)
@@ -3238,7 +3285,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3510,11 +3557,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		return 0;
+	cnt = tape->merge_stage_size / tape->tape_block_size;
+	if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+		++cnt;		/* Filemarks count as 1 sector */
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
 		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3526,9 +3577,14 @@
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
-	cnt = tape->nr_stages - tape->nr_pending_stages;
-	while (tape->first_stage != NULL)
+	while (tape->first_stage != NULL) {
+		struct request *rq_ptr = &tape->first_stage->rq;
+
+		cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; 
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			++cnt;
 		idetape_remove_stage_head(drive);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -4151,7 +4207,7 @@
 		 */
 		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -4164,7 +4220,7 @@
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
-	    tape->nr_stages <= max_stages) {
+	    tape->nr_stages < max_stages) {
 		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
@@ -4287,6 +4343,12 @@
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
+	 * If we are at a filemark, return a read length of 0
+	 */
+	if (test_bit(IDETAPE_FILEMARK, &tape->flags))
+		return 0;
+
+	/*
 	 * Wait for the next logical block to be available at the head
 	 * of the pipeline
 	 */
@@ -4315,14 +4377,7 @@
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit(IDETAPE_FILEMARK, &tape->flags);
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
-		calculate_speeds(drive);
-	} else {
+	else {
 		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
@@ -4331,7 +4386,8 @@
 					"bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit(IDETAPE_FILEMARK, &tape->flags);
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			set_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4714,6 +4770,14 @@
 		tape->restart_speed_control_req = 1;
 		return retval;
 	}
+ 
+	if (mt_count == 0)
+		return 0;
+	if (MTBSF == mt_op || MTBSFM == mt_op) {
+		if (!tape->capabilities.sprev)
+			return -EIO;
+		mt_count = - mt_count;
+	}
 
 	if (tape->chrdev_direction == idetape_direction_read) {
 		/*
@@ -4721,28 +4785,36 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit(IDETAPE_FILEMARK, &tape->flags);
+		if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+			++count;
 		while (tape->first_stage != NULL) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head(drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
+			if (tape->first_stage == tape->active_stage) {
+				/*
+				 *	We have reached the active stage in the read pipeline.
+				 *	There is no point in allowing the drive to continue
+				 *	reading any farther, so we stop the pipeline.
+				 *
+				 *	This section should be moved to a separate subroutine,
+				 *	because a similar function is performed in
+				 *	__idetape_discard_read_pipeline(), for example.
+				 */
+				tape->next_stage = NULL;
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+				idetape_wait_first_stage(drive);
+				tape->next_stage = tape->first_stage->next;
+			} else
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+				++count;
 			idetape_remove_stage_head(drive);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline(drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4751,25 +4823,17 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
+		case MTBSF:
 			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
 			return (idetape_queue_pc_tail(drive, &pc));
 		case MTFSFM:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
-			if (retval) return (retval);
-			return (idetape_space_over_filemarks(drive, MTBSF, 1));
-		case MTBSF:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			idetape_create_space_cmd(&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail(drive, &pc));
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks(drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks(drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
 			printk(KERN_ERR "ide-tape: MTIO operation %d not "
 				"supported\n", mt_op);
@@ -5117,7 +5181,7 @@
 		 */
 		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree(tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -5701,9 +5765,11 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
@@ -5776,10 +5842,11 @@
 	if (minor < 128)
 		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
 				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
@@ -5813,34 +5880,34 @@
 	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
 	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk(KERN_INFO "ATA\n");break;
-		case 2:	printk(KERN_INFO "ATAPI\n");break;
-		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk(KERN_INFO "Direct-access Device\n");break;
-		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
-		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk(KERN_INFO "Reserved\n");
-		case 7: printk(KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
-		default: printk(KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
 	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
 	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk(KERN_INFO "12 bytes\n");break;
-		case 1: printk(KERN_INFO "16 bytes\n");break;
-		default: printk(KERN_INFO "Reserved\n");break;
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
 	}
 	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
 	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
@@ -5856,44 +5923,44 @@
 	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk(KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk(KERN_INFO "\n");
+	printk("\n");
 	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk(KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk(KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk(KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
 		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
 		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk("%d ns\n",id->eide_dma_min);
 
 		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk("%d ns\n",id->eide_dma_time);
 
 		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_pio);
+			printk("%d ns\n",id->eide_pio);
 
 		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk(KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
 		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
@@ -6205,9 +6272,9 @@
  *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
  */
 	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
-	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
 	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
 	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
 	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
@@ -6317,8 +6384,11 @@
 	si_meminfo(&si);
 	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
-	tape->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_MIN(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+	if (tape->max_stages == 0)
+		tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
 
 	t1 = (tape->stage_size * HZ) / (speed * 1000);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
diff -urN linux-2.4.21-pre1/drivers/ide/ide.c linux-2.4.21-pre2/drivers/ide/ide.c
--- linux-2.4.21-pre1/drivers/ide/ide.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/ide.c	Wed Dec 18 14:16:27 2002
@@ -486,7 +486,7 @@
 		drive->part[p].nr_sects   = 0;
 	};
 
-	if (DRIVER(drive)->revalidate)
+	if (DRIVER(drive) && DRIVER(drive)->revalidate)
 		DRIVER(drive)->revalidate(drive);
 
 	drive->busy = 0;
diff -urN linux-2.4.21-pre1/drivers/ide/pci/adma100.c linux-2.4.21-pre2/drivers/ide/pci/adma100.c
--- linux-2.4.21-pre1/drivers/ide/pci/adma100.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/adma100.c	Wed Dec 18 14:16:27 2002
@@ -18,7 +18,7 @@
 
 void __init ide_init_adma100 (ide_hwif_t *hwif)
 {
-	u32  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	unsigned long  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
 	void *v_admctl;
 
 	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
diff -urN linux-2.4.21-pre1/drivers/ide/pci/adma100.h linux-2.4.21-pre2/drivers/ide/pci/adma100.h
--- linux-2.4.21-pre1/drivers/ide/pci/adma100.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/adma100.h	Wed Dec 18 14:16:27 2002
@@ -12,24 +12,24 @@
 
 static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
 	{
-		vendor:	PCI_VENDOR_ID_PDC,
-		device:	PCI_DEVICE_ID_PDC_1841,
-		name:		"ADMA100",
-		init_setup:	init_setup_pdcadma,
-		init_chipset:	init_chipset_pdcadma,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdcadma,
-		init_dma:	init_dma_pdcadma,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "ADMA100",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 }
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/aec62xx.c linux-2.4.21-pre2/drivers/ide/pci/aec62xx.c
--- linux-2.4.21-pre1/drivers/ide/pci/aec62xx.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/aec62xx.c	Wed Dec 18 14:16:27 2002
@@ -42,7 +42,7 @@
 
 	for (i = 0; i < n_aec_devs; i++) {
 		struct pci_dev *dev	= aec_devs[i];
-		u32 iobase		= pci_resource_start(dev, 4);
+		unsigned long iobase = pci_resource_start(dev, 4);
 		u8 c0 = 0, c1 = 0, art	= 0;
 #ifdef DEBUG_AEC_REGS
 		u8 uart			= 0;
@@ -493,7 +493,7 @@
 
 static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	u32 bar4reg = pci_resource_start(dev, 4);
+	unsigned long bar4reg = pci_resource_start(dev, 4);
 
 	if (inb(bar4reg+2) & 0x10) {
 		strcpy(d->name, "AEC6880");
diff -urN linux-2.4.21-pre1/drivers/ide/pci/aec62xx.h linux-2.4.21-pre2/drivers/ide/pci/aec62xx.h
--- linux-2.4.21-pre1/drivers/ide/pci/aec62xx.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/aec62xx.h	Wed Dec 18 14:16:27 2002
@@ -80,10 +80,10 @@
 
 static ide_pci_host_proc_t aec62xx_procs[] __initdata = {
 	{
-		name:		"aec62xx",
-		set:		1,
-		get_info:	aec62xx_get_info,
-		parent:		NULL,
+		.name		= "aec62xx",
+		.set		= 1,
+		.get_info	= aec62xx_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
@@ -96,75 +96,75 @@
 
 static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_ARTOP,
-		device:		PCI_DEVICE_ID_ARTOP_ATP850UF,
-		name:		"AEC6210",
-		init_setup:	init_setup_aec62xx,
-		init_chipset:	init_chipset_aec62xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_aec62xx,
-		init_dma:	init_dma_aec62xx,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP850UF,
+		.name		= "AEC6210",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_ARTOP,
-		device:		PCI_DEVICE_ID_ARTOP_ATP860,
-		name:		"AEC6260",
-		init_setup:	init_setup_aec62xx,
-		init_chipset:	init_chipset_aec62xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_aec62xx,
-		init_dma:	init_dma_aec62xx,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860,
+		.name		= "AEC6260",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_ARTOP,
-		device:		PCI_DEVICE_ID_ARTOP_ATP860R,
-		name:		"AEC6260R",
-		init_setup:	init_setup_aec62xx,
-		init_chipset:	init_chipset_aec62xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_aec62xx,
-		init_dma:	init_dma_aec62xx,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		bootable:	NEVER_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860R,
+		.name		= "AEC6260R",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 0,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_ARTOP,
-		device:		PCI_DEVICE_ID_ARTOP_ATP865,
-		name:		"AEC6X80",
-		init_setup:	init_setup_aec6x80,
-		init_chipset:	init_chipset_aec62xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_aec62xx,
-		init_dma:	init_dma_aec62xx,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865,
+		.name		= "AEC6X80",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_ARTOP,
-		device:		PCI_DEVICE_ID_ARTOP_ATP865R,
-		name:		"AEC6X80R",
-		init_setup:	init_setup_aec6x80,
-		init_chipset:	init_chipset_aec62xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_aec62xx,
-		init_dma:	init_dma_aec62xx,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865R,
+		.name		= "AEC6X80R",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/alim15x3.c linux-2.4.21-pre2/drivers/ide/pci/alim15x3.c
--- linux-2.4.21-pre1/drivers/ide/pci/alim15x3.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/alim15x3.c	Wed Dec 18 14:16:27 2002
@@ -94,7 +94,7 @@
  
 static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	u32 bibma;
+	unsigned long bibma;
 	u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
 	char *q, *p = buffer;
 
@@ -106,14 +106,15 @@
 		fifo[3]  = "   ???  ";
 
 	/* first fetch bibma: */
-	pci_read_config_dword(bmide_dev, 0x20, &bibma);
-	bibma = (bibma & 0xfff0) ;
+	
+	bibma = pci_resource_start(bmide_dev, 4);
+
 	/*
 	 * at that point bibma+0x2 et bibma+0xa are byte
 	 * registers to investigate:
 	 */
-	c0 = inb((unsigned short)bibma + 0x02);
-	c1 = inb((unsigned short)bibma + 0x0a);
+	c0 = inb(bibma + 0x02);
+	c1 = inb(bibma + 0x0a);
 
 	p += sprintf(p,
 		"\n                                Ali M15x3 Chipset.\n");
@@ -779,9 +780,10 @@
 static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
 {
 	u8 ideic, inmir;
-	u8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+	s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
 				      1, 11, 0, 12, 0, 14, 0, 15 };
-
+	int irq;
+	
 	hwif->irq = hwif->channel ? 15 : 14;
 
 	if (isa_dev) {
@@ -801,15 +803,17 @@
 			 */
 			pci_read_config_byte(isa_dev, 0x44, &inmir);
 			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
+			irq = irq_routing_table[inmir];
 		} else if (hwif->channel && !(ideic & 0x01)) {
 			/*
 			 * get SIRQ2 routing table
 			 */
 			pci_read_config_byte(isa_dev, 0x75, &inmir);
 			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
+			irq = irq_routing_table[inmir];
 		}
+		if(irq >= 0)
+			hwif->irq = irq;
 	}
 
 	init_hwif_common_ali15x3(hwif);
diff -urN linux-2.4.21-pre1/drivers/ide/pci/alim15x3.h linux-2.4.21-pre2/drivers/ide/pci/alim15x3.h
--- linux-2.4.21-pre1/drivers/ide/pci/alim15x3.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/alim15x3.h	Wed Dec 18 14:16:27 2002
@@ -17,10 +17,10 @@
 
 static ide_pci_host_proc_t ali_procs[] __initdata = {
 	{
-		name:		"ali",
-		set:		1,
-		get_info:	ali_get_info,
-		parent:		NULL,
+		.name		= "ali",
+		.set		= 1,
+		.get_info	= ali_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_ALI_TIMINGS && CONFIG_PROC_FS */
@@ -32,23 +32,23 @@
 
 static ide_pci_device_t ali15x3_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_AL,
-		device:		PCI_DEVICE_ID_AL_M5229,
-		name:		"ALI15X3",
-		init_chipset:	init_chipset_ali15x3,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_ali15x3,
-		init_dma:	init_dma_ali15x3,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_AL,
+		.device		= PCI_DEVICE_ID_AL_M5229,
+		.name		= "ALI15X3",
+		.init_chipset	= init_chipset_ali15x3,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ali15x3,
+		.init_dma	= init_dma_ali15x3,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cmd640.c linux-2.4.21-pre2/drivers/ide/pci/cmd640.c
--- linux-2.4.21-pre1/drivers/ide/pci/cmd640.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cmd640.c	Wed Dec 18 14:16:27 2002
@@ -751,7 +751,7 @@
 	 */
 	put_cmd640_reg(0x5b, 0xbd);
 	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
 		return 0;
 	}
 	put_cmd640_reg(0x5b, 0);
@@ -836,7 +836,7 @@
 		cmd_hwif1->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 	}
-	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
 		cmd_hwif0->serialized ? "" : "not ", port2);
 
 	/*
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cmd640.h linux-2.4.21-pre2/drivers/ide/pci/cmd640.h
--- linux-2.4.21-pre1/drivers/ide/pci/cmd640.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cmd640.h	Wed Dec 18 14:16:27 2002
@@ -9,23 +9,23 @@
 
 static ide_pci_device_t cmd640_chipsets[] __initdata = {
 	{
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_CMD_640,
-		name:		"CMD640",
-		init_setup:	NULL,
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	IDE_IGNORE,
-		init_dma:	NULL,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_640,
+		.name		= "CMD640",
+		.init_setup	= NULL,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= IDE_IGNORE,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
 	},{
-		vendor:		0,
-		device:		0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.bootable	= EOL,
 	}
 }
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cmd64x.h linux-2.4.21-pre2/drivers/ide/pci/cmd64x.h
--- linux-2.4.21-pre1/drivers/ide/pci/cmd64x.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cmd64x.h	Wed Dec 18 14:16:27 2002
@@ -71,10 +71,10 @@
 
 static ide_pci_host_proc_t cmd64x_procs[] __initdata = {
 	{
-		name:		"cmd64x",
-		set:		1,
-		get_info:	cmd64x_get_info,
-		parent:		NULL,
+		.name		= "cmd64x",
+		.set		= 1,
+		.get_info	= cmd64x_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -85,62 +85,62 @@
 
 static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_CMD_643,
-		name:		"CMD643",
-		init_chipset:	init_chipset_cmd64x,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_cmd64x,
-		init_dma:	init_dma_cmd64x,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_643,
+		.name		= "CMD643",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_CMD_646,
-		name:		"CMD646",
-		init_chipset:	init_chipset_cmd64x,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_cmd64x,
-		init_dma:	init_dma_cmd64x,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x51,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_646,
+		.name		= "CMD646",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:	PCI_DEVICE_ID_CMD_648,
-		name:		"CMD648",
-		init_chipset:	init_chipset_cmd64x,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_cmd64x,
-		init_dma:	init_dma_cmd64x,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device	= PCI_DEVICE_ID_CMD_648,
+		.name		= "CMD648",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_CMD_649,
-		name:		"CMD649",
-		init_chipset:	init_chipset_cmd64x,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_cmd64x,
-		init_dma:	init_dma_cmd64x,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_649,
+		.name		= "CMD649",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	2,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 2,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cs5530.c linux-2.4.21-pre2/drivers/ide/pci/cs5530.c
--- linux-2.4.21-pre1/drivers/ide/pci/cs5530.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cs5530.c	Wed Dec 18 14:16:27 2002
@@ -42,7 +42,7 @@
 static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
 	u8  c0 = 0, c1 = 0;
 
 	/*
@@ -124,7 +124,8 @@
 static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
 {
 	ide_hwif_t	*hwif = HWIF(drive);
-	unsigned int	format, basereg = CS5530_BASEREG(hwif);
+	unsigned int	format;
+	unsigned long basereg = CS5530_BASEREG(hwif);
 	static u8	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
 
 	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -151,7 +152,8 @@
 	int			unit = drive->select.b.unit;
 	ide_drive_t		*mate = &hwif->drives[unit^1];
 	struct hd_driveid	*id = drive->id;
-	unsigned int		basereg, reg, timings;
+	unsigned int		reg, timings;
+	unsigned long		basereg;
 
 	/*
 	 * Default to DMA-off in case we run into trouble here.
@@ -365,7 +367,8 @@
 
 static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
 {
-	unsigned int basereg, d0_timings;
+	unsigned long basereg;
+	u32 d0_timings;
 	hwif->autodma = 0;
 
 	if (hwif->mate)
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cs5530.h linux-2.4.21-pre2/drivers/ide/pci/cs5530.h
--- linux-2.4.21-pre1/drivers/ide/pci/cs5530.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cs5530.h	Wed Dec 18 14:16:27 2002
@@ -17,10 +17,10 @@
 
 static ide_pci_host_proc_t cs5530_procs[] __initdata = {
 	{
-		name:		"cs5530",
-		set:		1,
-		get_info:	cs5530_get_info,
-		parent:		NULL,
+		.name		= "cs5530",
+		.set		= 1,
+		.get_info	= cs5530_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
@@ -31,23 +31,23 @@
 
 static ide_pci_device_t cs5530_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_CYRIX,
-		device:		PCI_DEVICE_ID_CYRIX_5530_IDE,
-		name:		"CS5530",
-		init_chipset:	init_chipset_cs5530,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_cs5530,
-		init_dma:	init_dma_cs5530,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CYRIX,
+		.device		= PCI_DEVICE_ID_CYRIX_5530_IDE,
+		.name		= "CS5530",
+		.init_chipset	= init_chipset_cs5530,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cs5530,
+		.init_dma	= init_dma_cs5530,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/cy82c693.h linux-2.4.21-pre2/drivers/ide/pci/cy82c693.h
--- linux-2.4.21-pre1/drivers/ide/pci/cy82c693.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/cy82c693.h	Wed Dec 18 14:16:27 2002
@@ -70,23 +70,23 @@
 
 static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_CONTAQ,
-		device:		PCI_DEVICE_ID_CONTAQ_82C693,
-		name:		"CY82C693",
-		init_chipset:	init_chipset_cy82c693,
-		init_iops:	init_iops_cy82c693,
-		init_hwif:	init_hwif_cy82c693,
-		init_dma:	NULL,
-		channels:	1,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CONTAQ,
+		.device		= PCI_DEVICE_ID_CONTAQ_82C693,
+		.name		= "CY82C693",
+		.init_chipset	= init_chipset_cy82c693,
+		.init_iops	= init_iops_cy82c693,
+		.init_hwif	= init_hwif_cy82c693,
+		.init_dma	= NULL,
+		.channels	= 1,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/generic.h linux-2.4.21-pre2/drivers/ide/pci/generic.h
--- linux-2.4.21-pre1/drivers/ide/pci/generic.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/generic.h	Wed Dec 18 14:16:27 2002
@@ -11,149 +11,149 @@
 
 static ide_pci_device_t generic_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_NS,
-		device:		PCI_DEVICE_ID_NS_87410,
-		name:		"NS87410",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x43,0x08,0x08}, {0x47,0x08,0x08}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87410,
+		.name		= "NS87410",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
         },{	/* 1 */
-		vendor:		PCI_VENDOR_ID_PCTECH,
-		device:		PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
-		name:		"SAMURAI",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		.name		= "SAMURAI",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_HOLTEK,
-		device:		PCI_DEVICE_ID_HOLTEK_6565,
-		name:		"HT6565",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_HOLTEK,
+		.device		= PCI_DEVICE_ID_HOLTEK_6565,
+		.name		= "HT6565",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_UMC,
-		device:		PCI_DEVICE_ID_UMC_UM8673F,
-		name:		"UM8673F",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8673F,
+		.name		= "UM8673F",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_UMC,
-		device:		PCI_DEVICE_ID_UMC_UM8886A,
-		name:		"UM8886A",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886A,
+		.name		= "UM8886A",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 5 */
-		vendor:		PCI_VENDOR_ID_UMC,
-		device:		PCI_DEVICE_ID_UMC_UM8886BF,
-		name:		"UM8886BF",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886BF,
+		.name		= "UM8886BF",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 6 */
-		vendor:		PCI_VENDOR_ID_HINT,
-		device:		PCI_DEVICE_ID_HINT_VXPROII_IDE,
-		name:		"HINT_IDE",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_HINT,
+		.device		= PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		.name		= "HINT_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 7 */
-		vendor:		PCI_VENDOR_ID_VIA,
-		device:		PCI_DEVICE_ID_VIA_82C561,
-		name:		"VIA_IDE",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C561,
+		.name		= "VIA_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 8 */
-		vendor:		PCI_VENDOR_ID_OPTI,
-		device:		PCI_DEVICE_ID_OPTI_82C558,
-		name:		"OPTI621V",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C558,
+		.name		= "OPTI621V",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
 static ide_pci_device_t unknown_chipset[] __devinitdata = {
 	{	/* 0 */
-		vendor:		0,
-		device:		0,
-		name:		"PCI_IDE",
-		init_chipset:	init_chipset_generic,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_generic,
-		init_dma:	init_dma_generic,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= 0,
+		.device		= 0,
+		.name		= "PCI_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 
 };
diff -urN linux-2.4.21-pre1/drivers/ide/pci/hpt34x.c linux-2.4.21-pre2/drivers/ide/pci/hpt34x.c
--- linux-2.4.21-pre1/drivers/ide/pci/hpt34x.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/hpt34x.c	Wed Dec 18 14:16:27 2002
@@ -64,7 +64,7 @@
 			"HPT34X Chipset.\n");
 	for (i = 0; i < n_hpt34x_devs; i++) {
 		struct pci_dev *dev = hpt34x_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
+		unsigned long bibma = pci_resource_start(dev, 4);
 		u8  c0 = 0, c1 = 0;
 
 		/*
diff -urN linux-2.4.21-pre1/drivers/ide/pci/hpt34x.h linux-2.4.21-pre2/drivers/ide/pci/hpt34x.h
--- linux-2.4.21-pre1/drivers/ide/pci/hpt34x.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/hpt34x.h	Wed Dec 18 14:16:27 2002
@@ -23,10 +23,10 @@
 
 static ide_pci_host_proc_t hpt34x_procs[] __initdata = {
 	{
-		name:		"hpt34x",
-		set:		1,
-		get_info:	hpt34x_get_info,
-		parent:		NULL,
+		.name		= "hpt34x",
+		.set		= 1,
+		.get_info	= hpt34x_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -37,23 +37,23 @@
 
 static ide_pci_device_t hpt34x_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT343,
-		name:		"HPT34X",
-		init_chipset:	init_chipset_hpt34x,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt34x,
-		init_dma:	init_dma_hpt34x,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	NEVER_BOARD,
-		extra:		16
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT343,
+		.name		= "HPT34X",
+		.init_chipset	= init_chipset_hpt34x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt34x,
+		.init_dma	= init_dma_hpt34x,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 16
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/hpt366.c linux-2.4.21-pre2/drivers/ide/pci/hpt366.c
--- linux-2.4.21-pre1/drivers/ide/pci/hpt366.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/hpt366.c	Wed Dec 18 14:16:27 2002
@@ -659,7 +659,7 @@
 static void hpt3xx_reset (ide_drive_t *drive)
 {
 #if 0
-	u32 high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
 	u8 reset	= (HWIF(drive)->channel) ? 0x80 : 0x40;
 	u8 reg59h	= 0;
 
@@ -818,7 +818,10 @@
 	} else {
 		pll = F_LOW_PCI_66;
 		if (hpt_minimum_revision(dev,8))
+		{
+			printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
 			return -EOPNOTSUPP;
+		}
 		else if (hpt_minimum_revision(dev,5))
 			pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
 		else if (hpt_minimum_revision(dev,4))
diff -urN linux-2.4.21-pre1/drivers/ide/pci/hpt366.h linux-2.4.21-pre2/drivers/ide/pci/hpt366.h
--- linux-2.4.21-pre1/drivers/ide/pci/hpt366.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/hpt366.h	Wed Dec 18 14:16:27 2002
@@ -426,10 +426,10 @@
 
 static ide_pci_host_proc_t hpt366_procs[] __initdata = {
 	{
-		name:		"hpt366",
-		set:		1,
-		get_info:	hpt366_get_info,
-		parent:		NULL,
+		.name		= "hpt366",
+		.set		= 1,
+		.get_info	= hpt366_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -443,80 +443,80 @@
 
 static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT366,
-		name:		"HPT366",
-		init_setup:	init_setup_hpt366,
-		init_chipset:	init_chipset_hpt366,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt366,
-		init_dma:	init_dma_hpt366,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		240
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT366,
+		.name		= "HPT366",
+		.init_setup	= init_setup_hpt366,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT372,
-		name:		"HPT372A",
-		init_setup:	init_setup_hpt37x,
-		init_chipset:	init_chipset_hpt366,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt366,
-		init_dma:	init_dma_hpt366,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT372,
+		.name		= "HPT372A",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT302,
-		name:		"HPT302",
-		init_setup:	init_setup_hpt37x,
-		init_chipset:	init_chipset_hpt366,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt366,
-		init_dma:	init_dma_hpt366,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT302,
+		.name		= "HPT302",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT371,
-		name:		"HPT371",
-		init_setup:	init_setup_hpt37x,
-		init_chipset:	init_chipset_hpt366,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt366,
-		init_dma:	init_dma_hpt366,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT371,
+		.name		= "HPT371",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_TTI,
-		device:		PCI_DEVICE_ID_TTI_HPT374,
-		name:		"HPT374",
-		init_setup:	init_setup_hpt374,
-		init_chipset:	init_chipset_hpt366,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_hpt366,
-		init_dma:	init_dma_hpt366,
-		channels:	2,	/* 4 */
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT374,
+		.name		= "HPT374",
+		.init_setup	= init_setup_hpt374,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,	/* 4 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/it8172.h linux-2.4.21-pre2/drivers/ide/pci/it8172.h
--- linux-2.4.21-pre1/drivers/ide/pci/it8172.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/it8172.h	Wed Dec 18 14:16:27 2002
@@ -21,24 +21,24 @@
 
 static ide_pci_device_t it8172_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_ITE,
-		device:		PCI_DEVICE_ID_ITE_IT8172G,
-		name:		"IT8172G",
-		init_setup:	init_setup_it8172,
-		init_chipset:	init_chipset_it8172,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_it8172,
-                init_dma:	init_dma_it8172,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x40,0x00,0x01}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_ITE,
+		.device		= PCI_DEVICE_ID_ITE_IT8172G,
+		.name		= "IT8172G",
+		.init_setup	= init_setup_it8172,
+		.init_chipset	= init_chipset_it8172,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_it8172,
+                .init_dma	= init_dma_it8172,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/ns87415.h linux-2.4.21-pre2/drivers/ide/pci/ns87415.h
--- linux-2.4.21-pre1/drivers/ide/pci/ns87415.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/ns87415.h	Wed Dec 18 14:16:27 2002
@@ -10,23 +10,23 @@
 
 static ide_pci_device_t ns87415_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_NS,
-		device:		PCI_DEVICE_ID_NS_87415,
-		name:		"NS87415",
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_ns87415,
-                init_dma:	init_dma_ns87415,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87415,
+		.name		= "NS87415",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ns87415,
+                .init_dma	= init_dma_ns87415,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/opti621.h linux-2.4.21-pre2/drivers/ide/pci/opti621.h
--- linux-2.4.21-pre1/drivers/ide/pci/opti621.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/opti621.h	Wed Dec 18 14:16:27 2002
@@ -11,38 +11,38 @@
 
 static ide_pci_device_t opti621_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_OPTI,
-		device:		PCI_DEVICE_ID_OPTI_82C621,
-		name:		"OPTI621",
-		init_setup:	init_setup_opti621,
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_opti621,
-		init_dma:	init_dma_opti621,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x45,0x80,0x00}, {0x40,0x08,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C621,
+		.name		= "OPTI621",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+		.init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_OPTI,
-		device:		PCI_DEVICE_ID_OPTI_82C825,
-		name:		"OPTI621X",
-		init_setup:	init_setup_opti621,
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_opti621,
-                init_dma:	init_dma_opti621,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x45,0x80,0x00}, {0x40,0x08,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C825,
+		.name		= "OPTI621X",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+                .init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_new.c linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_new.c
--- linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_new.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_new.c	Wed Dec 18 14:16:27 2002
@@ -237,11 +237,11 @@
 static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	u32 indexreg		= hwif->dma_vendor1;
-	u32 datareg		= hwif->dma_vendor3;
+	unsigned long indexreg	= hwif->dma_vendor1;
+	unsigned long datareg	= hwif->dma_vendor3;
 	u8 thold		= 0x10;
 	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
-	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
 
 	if (speed == XFER_UDMA_2) {
 		hwif->OUTB((thold + adj), indexreg);
@@ -284,7 +284,7 @@
 {
 	u8 speed = 0;
 
-	pio = (pio == 5) ? 4 : pio;
+	if (pio == 5) pio = 4;
 	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
         
 	return ((int) pdcnew_tune_chipset(drive, speed));
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_new.h linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_new.h
--- linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_new.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_new.h	Wed Dec 18 14:16:27 2002
@@ -26,41 +26,6 @@
 	NULL
 };
 
-static inline u8 *pdcnew_pio_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
-	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
-	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
-	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
-	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
-	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
-	return("PIO ?");
-}
-
-static inline u8 *pdcnew_dma_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
-	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
-	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
-	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
-	return("PIO---");
-}
-
-static inline u8 *pdcnew_ultra_verbose (u32 drive_pci, u16 slow_cable)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000)
-		return("NOTSET");
-	if ((drive_pci & 0x00012000) == 0x00012000)
-		return((slow_cable) ? "UDMA 2" : "UDMA 4");
-	if ((drive_pci & 0x00024000) == 0x00024000)
-		return((slow_cable) ? "UDMA 1" : "UDMA 3");
-	if ((drive_pci & 0x00036000) == 0x00036000)
-		return("UDMA 0");
-	return(pdcnew_dma_verbose(drive_pci));
-}
-
 /* A Register */
 #define	SYNC_ERRDY_EN	0xC0
 
@@ -209,10 +174,10 @@
 
 static ide_pci_host_proc_t pdcnew_procs[] __initdata = {
 	{
-		name:		"pdcnew",
-		set:		1,
-		get_info:	pdcnew_get_info,
-		parent:		NULL,
+		.name		= "pdcnew",
+		.set		= 1,
+		.get_info	= pdcnew_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
@@ -227,116 +192,116 @@
 
 static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20268,
-		name:		"PDC20268",
-		init_setup:	init_setup_pdcnew,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20268,
+		.name		= "PDC20268",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20269,
-		name:		"PDC20269",
-		init_setup:	init_setup_pdcnew,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20269,
+		.name		= "PDC20269",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20270,
-		name:		"PDC20270",
-		init_setup:	init_setup_pdc20270,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20270,
+		.name		= "PDC20270",
+		.init_setup	= init_setup_pdc20270,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20271,
-		name:		"PDC20271",
-		init_setup:	init_setup_pdcnew,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20271,
+		.name		= "PDC20271",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20275,
-		name:		"PDC20275",
-		init_setup:	init_setup_pdcnew,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20275,
+		.name		= "PDC20275",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 5 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20276,
-		name:		"PDC20276",
-		init_setup:	init_setup_pdc20276,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20276,
+		.name		= "PDC20276",
+		.init_setup	= init_setup_pdc20276,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{	/* 6 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20277,
-		name:		"PDC20277",
-		init_setup:	init_setup_pdcnew,
-		init_chipset:	init_chipset_pdcnew,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202new,
-		init_dma:	init_dma_pdc202new,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20277,
+		.name		= "PDC20277",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_old.c linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_old.c
--- linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_old.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_old.c	Wed Dec 18 14:16:27 2002
@@ -64,7 +64,7 @@
 {
 	char *p = buf;
 
-	u32 bibma  = pci_resource_start(dev, 4);
+	unsigned long bibma  = pci_resource_start(dev, 4);
 	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
 	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
 	u8 hi = 0, lo = 0;
@@ -341,19 +341,14 @@
  * 180, 120,  90,  90,  90,  60,  30
  *  11,   5,   4,   3,   2,   1,   0
  */
-static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
 {
 	u8 speed = 0;
 
-	pio = (pio == 5) ? 4 : pio;
+	if (pio == 5) pio = 4;
 	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
         
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, u8 pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
+	pdc202xx_tune_chipset(drive, speed);
 }
 
 static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
@@ -540,9 +535,9 @@
 		struct request *rq	= HWGROUP(drive)->rq;
 		ide_hwif_t *hwif	= HWIF(drive);
 //		struct pci_dev *dev	= hwif->pci_dev;
-//		u32 high_16	= pci_resource_start(dev, 4);
-		u32 high_16	= hwif->dma_master;
-		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+//		unsgned long high_16	= pci_resource_start(dev, 4);
+		unsigned long high_16   = hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
 		u32 word_count	= 0;
 		u8 clock = hwif->INB(high_16 + 0x11);
 
@@ -560,10 +555,10 @@
 {
 	if (drive->addressing == 1) {
 		ide_hwif_t *hwif	= HWIF(drive);
-//		u32 high_16	= pci_resource_start(hwif->pci_dev, 4);
-		u32 high_16	= hwif->dma_master;
-		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
-		u8 clock	= 0;
+//		unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+		unsigned long high_16	= hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock		= 0;
 
 		hwif->OUTL(0, atapi_reg); /* zero out extra */
 		clock = hwif->INB(high_16 + 0x11);
@@ -577,7 +572,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 //	struct pci_dev *dev	= hwif->pci_dev;
 //	unsigned long high_16	= pci_resource_start(dev, 4);
-	u32 high_16		= hwif->dma_master;
+	unsigned long high_16	= hwif->dma_master;
 	u8 dma_stat		= hwif->INB(hwif->dma_status);
 	u8 sc1d			= hwif->INB((high_16 + 0x001d));
 
@@ -747,7 +742,7 @@
 static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
 {
 	hwif->autodma = 0;
-	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->tuneproc  = &config_chipset_for_pio;
 	hwif->quirkproc = &pdc202xx_quirkproc;
 
 	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_old.h linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_old.h
--- linux-2.4.21-pre1/drivers/ide/pci/pdc202xx_old.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdc202xx_old.h	Wed Dec 18 14:16:27 2002
@@ -209,10 +209,10 @@
 
 static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
 	{
-		name:		"pdc202xx",
-		set:		1,
-		get_info:	pdc202xx_get_info,
-		parent:		NULL,
+		.name		= "pdc202xx",
+		.set		= 1,
+		.get_info	= pdc202xx_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
@@ -227,99 +227,99 @@
 
 static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20246,
-		name:		"PDC20246",
-		init_setup:	init_setup_pdc202ata4,
-		init_chipset:	init_chipset_pdc202xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202xx,
-		init_dma:	init_dma_pdc202xx,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20246,
+		.name		= "PDC20246",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		16,
+		.bootable	= OFF_BOARD,
+		.extra		= 16,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20262,
-		name:		"PDC20262",
-		init_setup:	init_setup_pdc202ata4,
-		init_chipset:	init_chipset_pdc202xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202xx,
-		init_dma:	init_dma_pdc202xx,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20262,
+		.name		= "PDC20262",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		48,
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20263,
-		name:		"PDC20263",
-		init_setup:	init_setup_pdc202ata4,
-		init_chipset:	init_chipset_pdc202xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202xx,
-		init_dma:	init_dma_pdc202xx,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20263,
+		.name		= "PDC20263",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		48,
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20265,
-		name:		"PDC20265",
-		init_setup:	init_setup_pdc20265,
-		init_chipset:	init_chipset_pdc202xx,
-		init_hwif:	init_hwif_pdc202xx,
-		init_dma:	init_dma_pdc202xx,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20265,
+		.name		= "PDC20265",
+		.init_setup	= init_setup_pdc20265,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		48,
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_PROMISE,
-		device:		PCI_DEVICE_ID_PROMISE_20267,
-		name:		"PDC20267",
-		init_setup:	init_setup_pdc202xx,
-		init_chipset:	init_chipset_pdc202xx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdc202xx,
-		init_dma:	init_dma_pdc202xx,
-		channels:	2,
-		autodma:	AUTODMA,
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20267,
+		.name		= "PDC20267",
+		.init_setup	= init_setup_pdc202xx,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
 #ifdef CONFIG_PDC202XX_FORCE
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 #else /* !CONFIG_PDC202XX_FORCE */
-		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
 #endif
-		bootable:	OFF_BOARD,
-		extra:		48,
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdcadma.c linux-2.4.21-pre2/drivers/ide/pci/pdcadma.c
--- linux-2.4.21-pre1/drivers/ide/pci/pdcadma.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdcadma.c	Wed Dec 18 14:16:27 2002
@@ -43,7 +43,7 @@
 
 	for (i = 0; i < n_pdc_devs; i++) {
 		struct pci_dev *dev	= pdc_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
+		unsigned long bibma = pci_resource_start(dev, 4);
 
 		p += sprintf(p, "\n                                "
 			"PDC ADMA %04X Chipset.\n", dev->device);
diff -urN linux-2.4.21-pre1/drivers/ide/pci/pdcadma.h linux-2.4.21-pre2/drivers/ide/pci/pdcadma.h
--- linux-2.4.21-pre1/drivers/ide/pci/pdcadma.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/pdcadma.h	Wed Dec 18 14:16:27 2002
@@ -17,10 +17,10 @@
 
 static ide_pci_host_proc_t pdcadma_procs[] __initdata = {
 	{
-		name:		"pdcadma",
-		set:		1,
-		get_info:	pdcadma_get_info,
-		parent:		NULL,
+		.name		= "pdcadma",
+		.set		= 1,
+		.get_info	= pdcadma_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -32,24 +32,24 @@
 
 static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_PDC,
-		device:		PCI_DEVICE_ID_PDC_1841,
-		name:		"PDCADMA",
-		init_setup:	init_setup_pdcadma,
-		init_chipset:	init_chipset_pdcadma,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_pdcadma,
-		init_dma:	init_dma_pdcadma,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	OFF_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "PDCADMA",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/piix.c linux-2.4.21-pre2/drivers/ide/pci/piix.c
--- linux-2.4.21-pre1/drivers/ide/pci/piix.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/piix.c	Wed Dec 18 14:16:27 2002
@@ -96,7 +96,7 @@
 
 	for (i = 0; i < n_piix_devs; i++) {
 		struct pci_dev *dev	= piix_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
+		unsigned long bibma = pci_resource_start(dev, 4);
 	        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
 		u8  c0 = 0, c1 = 0, reg54 = 0, reg55 = 0;
 		u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
@@ -155,8 +155,8 @@
 		 * at that point bibma+0x2 et bibma+0xa are byte registers
 		 * to investigate:
 		 */
-		c0 = inb((unsigned short)bibma + 0x02);
-		c1 = inb((unsigned short)bibma + 0x0a);
+		c0 = inb(bibma + 0x02);
+		c1 = inb(bibma + 0x0a);
 
 		p += sprintf(p, "--------------- Primary Channel "
 				"---------------- Secondary Channel "
diff -urN linux-2.4.21-pre1/drivers/ide/pci/piix.h linux-2.4.21-pre2/drivers/ide/pci/piix.h
--- linux-2.4.21-pre1/drivers/ide/pci/piix.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/piix.h	Wed Dec 18 14:16:27 2002
@@ -19,10 +19,10 @@
 
 static ide_pci_host_proc_t piix_procs[] __devinitdata = {
 	{
-		name:		"piix",
-		set:		1,
-		get_info:	piix_get_info,
-		parent:		NULL,
+		.name		= "piix",
+		.set		= 1,
+		.get_info	= piix_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -40,235 +40,235 @@
  
 static ide_pci_device_t piix_pci_info[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82371FB_0,
-		name:		"PIIXa",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_0,
+		.name		= "PIIXa",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82371FB_1,
-		name:		"PIIXb",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_1,
+		.name		= "PIIXb",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82371MX,
-		name:		"MPIIX",
-		init_setup:	init_setup_piix,
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	NULL,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371MX,
+		.name		= "MPIIX",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82371SB_1,
-		name:		"PIIX3",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371SB_1,
+		.name		= "PIIX3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 4 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82371AB,
-		name:		"PIIX4",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371AB,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 5 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801AB_1,
-		name:		"ICH0",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AB_1,
+		.name		= "ICH0",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 6 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82443MX_1,
-		name:		"PIIX4",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82443MX_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 7 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801AA_1,
-		name:		"ICH",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AA_1,
+		.name		= "ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 8 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82372FB_1,
-		name:		"PIIX4",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82372FB_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 9 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82451NX,
-		name:		"PIIX4",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82451NX,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 10 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801BA_9,
-		name:		"ICH2",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_9,
+		.name		= "ICH2",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 11 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801BA_8,
-		name:		"ICH2M",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_8,
+		.name		= "ICH2M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 12 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801CA_10,
-		name:		"ICH3M",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_10,
+		.name		= "ICH3M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 13 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801CA_11,
-		name:		"ICH3",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_11,
+		.name		= "ICH3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 14 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801DB_11,
-		name:		"ICH4",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801DB_11,
+		.name		= "ICH4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 15 */
-		vendor:		PCI_VENDOR_ID_INTEL,
-		device:		PCI_DEVICE_ID_INTEL_82801E_11,
-		name:		"C-ICH",
-		init_setup:	init_setup_piix,
-		init_chipset:	init_chipset_piix,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_piix,
-		init_dma:	init_dma_piix,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801E_11,
+		.name		= "C-ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		init_setup:	NULL,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.init_setup	= NULL,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/rz1000.h linux-2.4.21-pre2/drivers/ide/pci/rz1000.h
--- linux-2.4.21-pre1/drivers/ide/pci/rz1000.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/rz1000.h	Wed Dec 18 14:16:27 2002
@@ -9,36 +9,36 @@
 
 static ide_pci_device_t rz1000_chipsets[] __devinitdata = {
 {
-		vendor:		PCI_VENDOR_ID_PCTECH,
-		device:		PCI_DEVICE_ID_PCTECH_RZ1000,
-		name:		"RZ1000",
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_rz1000,
-		init_dma:	NULL,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1000,
+		.name		= "RZ1000",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		PCI_VENDOR_ID_PCTECH,
-		device:		PCI_DEVICE_ID_PCTECH_RZ1001,
-		name:		"RZ1001",
-		init_chipset:	NULL,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_rz1000,
-		init_dma:	NULL,
-		channels:	2,
-		autodma:	NODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1001,
+		.name		= "RZ1001",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/sc1200.c linux-2.4.21-pre2/drivers/ide/pci/sc1200.c
--- linux-2.4.21-pre1/drivers/ide/pci/sc1200.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/sc1200.c	Wed Dec 18 14:16:27 2002
@@ -83,7 +83,7 @@
 static int sc1200_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
 	u8  c0 = 0, c1 = 0;
 
 	/*
@@ -91,8 +91,8 @@
 	 * to investigate:
 	 */
 
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
 
 	p += sprintf(p, "\n                               National SCx200 Chipset.\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
diff -urN linux-2.4.21-pre1/drivers/ide/pci/serverworks.c linux-2.4.21-pre2/drivers/ide/pci/serverworks.c
--- linux-2.4.21-pre1/drivers/ide/pci/serverworks.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/serverworks.c	Wed Dec 18 14:16:27 2002
@@ -61,7 +61,7 @@
 
 	for (i = 0; i < n_svwks_devs; i++) {
 		struct pci_dev *dev = svwks_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
+		unsigned long bibma = pci_resource_start(dev, 4);
 		u32 reg40, reg44;
 		u16 reg48, reg56;
 		u8  reg54, c0=0, c1=0;
@@ -76,8 +76,8 @@
 		 * at that point bibma+0x2 et bibma+0xa are byte registers
 		 * to investigate:
 		 */
-		c0 = inb_p((unsigned short)bibma + 0x02);
-		c1 = inb_p((unsigned short)bibma + 0x0a);
+		c0 = inb_p(bibma + 0x02);
+		c1 = inb_p(bibma + 0x0a);
 
 		p += sprintf(p, "\n                            ServerWorks ");
 		switch(dev->device) {
@@ -807,8 +807,8 @@
 	.id_table	= svwks_pci_tbl,
 	.probe		= svwks_init_one,
 #if 0	/* FIXME: implement */
-	suspend:	,
-	resume:		,
+	.suspend	= ,
+	.resume		= ,
 #endif
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/serverworks.h linux-2.4.21-pre2/drivers/ide/pci/serverworks.h
--- linux-2.4.21-pre1/drivers/ide/pci/serverworks.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/serverworks.h	Wed Dec 18 14:16:27 2002
@@ -23,10 +23,10 @@
 
 static ide_pci_host_proc_t svwks_procs[] __initdata = {
 {
-		name:		"svwks",
-		set:		1,
-		get_info:	svwks_get_info,
-		parent:		NULL,
+		.name		= "svwks",
+		.set		= 1,
+		.get_info	= svwks_get_info,
+		.parent		= NULL,
 	},
 };
 #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -39,66 +39,66 @@
 
 static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_SERVERWORKS,
-		device:		PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
-		name:		"SvrWks OSB4",
-		init_setup:	init_setup_svwks,
-		init_chipset:	init_chipset_svwks,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_svwks,
-		init_dma:	NULL,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		.name		= "SvrWks OSB4",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_SERVERWORKS,
-		device:		PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
-		name:		"SvrWks CSB5",
-		init_setup:	init_setup_svwks,
-		init_chipset:	init_chipset_svwks,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_svwks,
-		init_dma:	init_dma_svwks,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		.name		= "SvrWks CSB5",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 2 */
-		vendor:		PCI_VENDOR_ID_SERVERWORKS,
-		device:		PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
-		name:		"SvrWks CSB6",
-		init_setup:	init_setup_csb6,
-		init_chipset:	init_chipset_svwks,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_svwks,
-		init_dma:	init_dma_svwks,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 3 */
-		vendor:		PCI_VENDOR_ID_SERVERWORKS,
-		device:		PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
-		name:		"SvrWks CSB6",
-		init_setup:	init_setup_csb6,
-		init_chipset:	init_chipset_svwks,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_svwks,
-		init_dma:	init_dma_svwks,
-		channels:	1,	/* 2 */
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 1,	/* 2 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/siimage.c linux-2.4.21-pre2/drivers/ide/pci/siimage.c
--- linux-2.4.21-pre1/drivers/ide/pci/siimage.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/siimage.c	Wed Dec 18 14:16:27 2002
@@ -31,15 +31,15 @@
 {
 	char *p		= buf;
 	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;
-	u32 bmdma	= (mmio) ? ((u32) pci_get_drvdata(dev)) :
+	unsigned long bmdma	= (mmio) ? ((unsigned long) pci_get_drvdata(dev)) :
 				    (pci_resource_start(dev, 4));
 
 	p += sprintf(p, "\nController: %d\n", index);
 	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
 	if (mmio)
-		p += sprintf(p, "MMIO Base 0x%08x\n", bmdma);
-	p += sprintf(p, "%s-DMA Base 0x%08x\n", (mmio)?"MMIO":"BM", bmdma);
-	p += sprintf(p, "%s-DMA Base 0x%08x\n", (mmio)?"MMIO":"BM", bmdma+8);
+		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);
 
 	p += sprintf(p, "--------------- Primary Channel "
 			"---------------- Secondary Channel "
@@ -517,10 +517,10 @@
 #ifdef CONFIG_TRY_MMIO_SIIMAGE
 static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
 {
-	u32 bar5	= pci_resource_start(dev, 5);
-	u32 end5	= pci_resource_end(dev, 5);
+	unsigned long bar5	= pci_resource_start(dev, 5);
+	unsigned long end5	= pci_resource_end(dev, 5);
 	u8 tmpbyte	= 0;
-	u32 addr;
+	unsigned long addr;
 	void *ioaddr;
 
 	ioaddr = ioremap_nocache(bar5, (end5 - bar5));
@@ -529,8 +529,8 @@
 		return 0;
 
 	pci_set_master(dev);
-	addr = (u32) ioaddr;
-	pci_set_drvdata(dev, (void *) addr);
+	pci_set_drvdata(dev, ioaddr);
+	addr = (unsigned long) ioaddr;
 
 	if (dev->device == PCI_DEVICE_ID_SII_3112) {
 		sii_outl(0, DEVADDR(0x148));
@@ -653,7 +653,7 @@
 static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
-	u32 addr		= (u32) pci_get_drvdata(hwif->pci_dev);
+	unsigned long addr	= (unsigned long) pci_get_drvdata(hwif->pci_dev);
 	u8 ch			= hwif->channel;
 //	u16 i			= 0;
 	hw_regs_t hw;
diff -urN linux-2.4.21-pre1/drivers/ide/pci/siimage.h linux-2.4.21-pre2/drivers/ide/pci/siimage.h
--- linux-2.4.21-pre1/drivers/ide/pci/siimage.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/siimage.h	Wed Dec 18 14:16:27 2002
@@ -31,61 +31,59 @@
 
 #define ADJREG(B,R)	((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio)))))
 #define SELREG(R)	ADJREG((0xA0),(R))
-#define SELADDR(R)	((((u32)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
-#define HWIFADDR(R)	((((u32)hwif->hwif_data)*(hwif->mmio))|(R))
-#define DEVADDR(R)	(((u32) pci_get_drvdata(dev))|(R))
+#define SELADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
+#define HWIFADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|(R))
+#define DEVADDR(R)	(((unsigned long) pci_get_drvdata(dev))|(R))
 
 
-inline u8 sii_inb (u32 port)
+inline u8 sii_inb (unsigned long port)
 {
 	return (u8) readb(port);
 }
 
-inline u16 sii_inw (u32 port)
+inline u16 sii_inw (unsigned long port)
 {
 	return (u16) readw(port);
 }
 
-inline void sii_insw (u32 port, void *addr, u32 count)
+inline void sii_insw (unsigned long port, void *addr, u32 count)
 {
-	while (count--) { *(u16 *)addr = readw(port); addr += 2; }
+	__ide_mm_insw(port, addr, count);
 }
 
-inline u32 sii_inl (u32 port)
+inline u32 sii_inl (unsigned long port)
 {
 	return (u32) readl(port);
 }
 
-inline void sii_insl (u32 port, void *addr, u32 count)
+inline void sii_insl (unsigned long port, void *addr, u32 count)
 {
-	sii_insw(port, addr, (count)<<1);
-//	while (count--) { *(u32 *)addr = readl(port); addr += 4; }
+	__ide_mm_insw(port, addr, (count)<<1);
 }
 
-inline void sii_outb (u8 value, u32 port)
+inline void sii_outb (u8 value, unsigned long port)
 {
 	writeb(value, port);
 }
 
-inline void sii_outw (u16 value, u32 port)
+inline void sii_outw (u16 value, unsigned long port)
 {
 	writew(value, port);
 }
 
-inline void sii_outsw (u32 port, void *addr, u32 count)
+inline void sii_outsw (unsigned long port, void *addr, u32 count)
 {
-	while (count--) { writew(*(u16 *)addr, port); addr += 2; }
+	__ide_mm_outsw(port, addr, count);
 }
 
-inline void sii_outl (u32 value, u32 port)
+inline void sii_outl (u32 value, unsigned long port)
 {
 	writel(value, port);
 }
 
-inline void sii_outsl (u32 port, void *addr, u32 count)
+inline void sii_outsl (unsigned long port, void *addr, u32 count)
 {
-	sii_outsw(port, addr, (count)<<1);
-//	while (count--) { writel(*(u32 *)addr, port); addr += 4; }
+	__ide_mm_outsw(port, addr, (count)<<1);
 }
 
 #if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
@@ -99,10 +97,10 @@
 
 static ide_pci_host_proc_t siimage_procs[] __initdata = {
 	{
-		name:		"siimage",
-		set:		1,
-		get_info:	siimage_get_info,
-		parent:		NULL,
+		.name		= "siimage",
+		.set		= 1,
+		.get_info	= siimage_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */	
@@ -114,36 +112,36 @@
 
 static ide_pci_device_t siimage_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_SII_680,
-		name:		"SiI680",
-		init_chipset:	init_chipset_siimage,
-		init_iops:	init_iops_siimage,
-		init_hwif:	init_hwif_siimage,
-		init_dma:	init_dma_siimage,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_680,
+		.name		= "SiI680",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_CMD,
-		device:		PCI_DEVICE_ID_SII_3112,
-		name:		"SiI3112 Serial ATA",
-		init_chipset:	init_chipset_siimage,
-		init_iops:	init_iops_siimage,
-		init_hwif:	init_hwif_siimage,
-		init_dma:	init_dma_siimage,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_3112,
+		.name		= "SiI3112 Serial ATA",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/sis5513.c linux-2.4.21-pre2/drivers/ide/pci/sis5513.c
--- linux-2.4.21-pre1/drivers/ide/pci/sis5513.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/sis5513.c	Wed Dec 18 14:16:27 2002
@@ -10,7 +10,7 @@
  *
  * SiS Taiwan		: for direct support and hardware.
  * Daniela Engert	: for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul, Dave Morgan :
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt	:
  *			  for checking code correctness, providing patches.
  *
  *
@@ -21,15 +21,20 @@
  */
 
 /*
- * TODO:
- *	- Get ridden of SisHostChipInfo[] completness dependancy.
- *	- Study drivers/ide/ide-timing.h.
- *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
- *	  or remove ATA_00 define
- *	- More checks in the config registers (force values instead of
- *	  relying on the BIOS setting them correctly).
- *	- Further optimisations ?
- *	  . for example ATA66+ regs 0x48 & 0x4A
+ * Notes/Special cases:
+ * - SiS5513 derivatives usually have the same PCI IDE register layout when
+ *  supporting the same UDMA modes.
+ * - There are exceptions :
+ *  . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support
+ *   ATA_100
+ *  . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously
+ *   south and northbridge were integrated, making IDE (a southbridge function)
+ *   capabilities easily deduced from the northbridge PCI id. With ATA_133,
+ *   chipsets started to be split in the usual north/south bridges chips
+ *   -> the driver needs to detect the correct southbridge when faced to newest
+ *   northbridges.
+ *  . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the
+ *   configuration space is moved from 0x40 to 0x70.
  */
 
 #include <linux/config.h>
@@ -298,6 +303,7 @@
 static char* get_drives_info (char *buffer, u8 pos)
 {
 	u8 reg00, reg01, reg10, reg11; /* timing registers */
+	u32 regdw0, regdw1;
 	char* p = buffer;
 
 /* Postwrite/Prefetch */
@@ -313,13 +319,31 @@
 		pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
 		pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
 		pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+	} else {
+		u32 reg54h;
+		u8 drive_pci = 0x40;
+		pci_read_config_dword(bmide_dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) {
+			// Configuration space remapped to 0x70
+			drive_pci = 0x70;
+		}
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos, &regdw0);
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos+4, &regdw1);
+		p += sprintf(p, "Drive %d:\n", pos);
 	}
 
 
 /* UDMA */
-	if (chipset_family >= ATA_33) {
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (regdw0 & 0x04) ? "Enabled" : "Disabled",
+			     (regdw1 & 0x04) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+			     cycle_time[(regdw0 & 0xF0) >> 4],
+			     cycle_time[(regdw1 & 0xF0) >> 4]);
+	} else if (chipset_family >= ATA_33) {
 		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
+			     (reg01 & 0x80) ? "Enabled" : "Disabled",
 			     (reg11 & 0x80) ? "Enabled" : "Disabled");
 
 		p += sprintf(p, "                UDMA Cycle Time    ");
@@ -659,13 +683,11 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 
-	u8 drive_pci, reg;
+	u8 drive_pci, reg, speed;
 	u32 regdw;
 
 #ifdef DEBUG
 	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
-	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
-	       drive->dn, speed);
 #endif
 
 #ifdef BROKEN_LEVEL
@@ -675,7 +697,12 @@
 	if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
 #endif
 
-	u8 speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+	speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+#ifdef DEBUG
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, xferspeed);
+#endif
 
 	/* See config_art_rwp_pio for drive pci config registers */
 	drive_pci = 0x40;
@@ -770,7 +797,7 @@
 	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
 
 #ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x, udma_66 %x\n",
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
 	       drive->dn, drive->id->dma_ultra);
 #endif
 
@@ -1057,3 +1084,16 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
+ */
+
diff -urN linux-2.4.21-pre1/drivers/ide/pci/sis5513.h linux-2.4.21-pre2/drivers/ide/pci/sis5513.h
--- linux-2.4.21-pre1/drivers/ide/pci/sis5513.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/sis5513.h	Wed Dec 18 14:16:27 2002
@@ -17,10 +17,10 @@
 
 static ide_pci_host_proc_t sis_procs[] __initdata = {
 {
-		name:		"sis",
-		set:		1,
-		get_info:	sis_get_info,
-		parent:		NULL,
+		.name		= "sis",
+		.set		= 1,
+		.get_info	= sis_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -31,23 +31,23 @@
 
 static ide_pci_device_t sis5513_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_SI,
-		device:		PCI_DEVICE_ID_SI_5513,
-		name:		"SIS5513",
-		init_chipset:	init_chipset_sis5513,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_sis5513,
-		init_dma:	init_dma_sis5513,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		bootable:	ON_BOARD,
-		extra:		0
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_5513,
+		.name		= "SIS5513",
+		.init_chipset	= init_chipset_sis5513,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sis5513,
+		.init_dma	= init_dma_sis5513,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/sl82c105.h linux-2.4.21-pre2/drivers/ide/pci/sl82c105.h
--- linux-2.4.21-pre1/drivers/ide/pci/sl82c105.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/sl82c105.h	Wed Dec 18 14:16:27 2002
@@ -11,23 +11,23 @@
 
 static ide_pci_device_t sl82c105_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_WINBOND,
-		device:		PCI_DEVICE_ID_WINBOND_82C105,
-		name:		"W82C105",
-		init_chipset:	init_chipset_sl82c105,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_sl82c105,
-		init_dma:	init_dma_sl82c105,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x40,0x01,0x01}, {0x40,0x10,0x10}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_WINBOND,
+		.device		= PCI_DEVICE_ID_WINBOND_82C105,
+		.name		= "W82C105",
+		.init_chipset	= init_chipset_sl82c105,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sl82c105,
+		.init_dma	= init_dma_sl82c105,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/slc90e66.c linux-2.4.21-pre2/drivers/ide/pci/slc90e66.c
--- linux-2.4.21-pre1/drivers/ide/pci/slc90e66.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/slc90e66.c	Wed Dec 18 14:16:27 2002
@@ -34,7 +34,7 @@
 static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
         u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
 	u8  c0 = 0, c1 = 0;
 	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
diff -urN linux-2.4.21-pre1/drivers/ide/pci/slc90e66.h linux-2.4.21-pre2/drivers/ide/pci/slc90e66.h
--- linux-2.4.21-pre1/drivers/ide/pci/slc90e66.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/slc90e66.h	Wed Dec 18 14:16:27 2002
@@ -19,10 +19,10 @@
 
 static ide_pci_host_proc_t slc90e66_procs[] __initdata = {
 	{
-		name:		"slc90e66",
-		set:		1,
-		get_info:	slc90e66_get_info,
-		parent:		NULL,
+		.name		= "slc90e66",
+		.set		= 1,
+		.get_info	= slc90e66_get_info,
+		.parent		= NULL,
 	},
 };
 #endif	/* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -33,23 +33,23 @@
 
 static ide_pci_device_t slc90e66_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_EFAR,
-		device:		PCI_DEVICE_ID_EFAR_SLC90E66_1,
-		name:		"SLC90E66",
-		init_chipset:	init_chipset_slc90e66,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_slc90e66,
-		init_dma:	init_dma_slc90e66,
-		channels:	2,
-		autodma:	AUTODMA,
-		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_EFAR,
+		.device		= PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		.name		= "SLC90E66",
+		.init_chipset	= init_chipset_slc90e66,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_slc90e66,
+		.init_dma	= init_dma_slc90e66,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/pci/via82cxxx.h linux-2.4.21-pre2/drivers/ide/pci/via82cxxx.h
--- linux-2.4.21-pre1/drivers/ide/pci/via82cxxx.h	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/pci/via82cxxx.h	Wed Dec 18 14:16:27 2002
@@ -17,10 +17,10 @@
 
 static ide_pci_host_proc_t via_procs[] __initdata = {
 	{
-		name:		"via",
-		set:		1,
-		get_info:	via_get_info,
-		parent:		NULL,
+		.name		= "via",
+		.set		= 1,
+		.get_info	= via_get_info,
+		.parent		= NULL,
 	},
 };
 #endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
@@ -31,36 +31,36 @@
 
 static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
 	{	/* 0 */
-		vendor:		PCI_VENDOR_ID_VIA,
-		device:		PCI_DEVICE_ID_VIA_82C576_1,
-		name:		"VP_IDE",
-		init_chipset:	init_chipset_via82cxxx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_via82cxxx,
-		init_dma:	init_dma_via82cxxx,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C576_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{	/* 1 */
-		vendor:		PCI_VENDOR_ID_VIA,
-		device:		PCI_DEVICE_ID_VIA_82C586_1,
-		name:		"VP_IDE",
-		init_chipset:	init_chipset_via82cxxx,
-		init_iops:	NULL,
-		init_hwif:	init_hwif_via82cxxx,
-		init_dma:	init_dma_via82cxxx,
-		channels:	2,
-		autodma:	NOAUTODMA,
-		enablebits:	{{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-		bootable:	ON_BOARD,
-		extra:		0,
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C586_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
 	},{
-		vendor:		0,
-		device:		0,
-		channels:	0,
-		bootable:	EOL,
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
 	}
 };
 
diff -urN linux-2.4.21-pre1/drivers/ide/setup-pci.c linux-2.4.21-pre2/drivers/ide/setup-pci.c
--- linux-2.4.21-pre1/drivers/ide/setup-pci.c	Wed Dec 18 14:16:24 2002
+++ linux-2.4.21-pre2/drivers/ide/setup-pci.c	Wed Dec 18 14:16:27 2002
@@ -477,7 +477,7 @@
 	if ((d->autodma == AUTODMA) ||
 	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
 	     (dev->class & 0x80))) {
-		u32 dma_base = ide_get_or_set_dma_base(hwif);
+		unsigned long dma_base = ide_get_or_set_dma_base(hwif);
 		if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
 			/*
  			 * Set up BM-DMA capability
diff -urN linux-2.4.21-pre1/drivers/ieee1394/Makefile linux-2.4.21-pre2/drivers/ieee1394/Makefile
--- linux-2.4.21-pre1/drivers/ieee1394/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/Makefile	Wed Dec 18 14:16:27 2002
@@ -2,11 +2,8 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
-O_TARGET := ieee1394drv.o
-
 export-objs := ieee1394_core.o ohci1394.o cmp.o
 
-list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
 		 highlevel.o csr.o nodemgr.o
 
diff -urN linux-2.4.21-pre1/drivers/ieee1394/amdtp.c linux-2.4.21-pre2/drivers/ieee1394/amdtp.c
--- linux-2.4.21-pre1/drivers/ieee1394/amdtp.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/amdtp.c	Wed Dec 18 14:16:27 2002
@@ -834,7 +834,8 @@
 
 	max_packet_size = max_nevents * s->dimension * 4 + 8;
 	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
-					 max_packet_size, 0, 0, SLAB_KERNEL);
+					 max_packet_size, 0, 0 ,SLAB_KERNEL);
+
 	if (s->packet_pool == NULL)
 		return -1;
 
@@ -1021,6 +1022,7 @@
 	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
 					     sizeof(struct descriptor_block),
 					     16, 0, SLAB_KERNEL);
+
 	if (s->descriptor_pool == NULL) {
 		kfree(s->input);
 		kfree(s);
diff -urN linux-2.4.21-pre1/drivers/ieee1394/cmp.c linux-2.4.21-pre2/drivers/ieee1394/cmp.c
--- linux-2.4.21-pre1/drivers/ieee1394/cmp.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/cmp.c	Wed Dec 18 14:16:27 2002
@@ -199,7 +199,7 @@
 }
 
 static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		    u64 addr, unsigned int length)
+		    u64 addr, unsigned int length, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
@@ -235,7 +235,7 @@
 }
 
 static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
diff -urN linux-2.4.21-pre1/drivers/ieee1394/csr.c linux-2.4.21-pre2/drivers/ieee1394/csr.c
--- linux-2.4.21-pre1/drivers/ieee1394/csr.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/csr.c	Wed Dec 18 14:16:27 2002
@@ -4,20 +4,33 @@
  * CSR implementation, iso/bus manager implementation.
  *
  * Copyright (C) 1999 Andreas E. Bombe
+ *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *
  */
 
 #include <linux/string.h>
+#include <linux/module.h> /* needed for MODULE_PARM */
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
 
+/* Module Parameters */
+/* this module parameter can be used to disable mapping of the FCP registers */
+MODULE_PARM(fcp,"i");
+MODULE_PARM_DESC(fcp, "FCP-registers");
+static int fcp = 1;
 
-/* FIXME: this one won't work on little endian with big endian data */
 static u16 csr_crc16(unsigned *data, int length)
 {
         int check=0, i;
@@ -25,7 +38,7 @@
 
         for (i = length; i; i--) {
                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
                 }
                 check = next & 0xffff;
@@ -60,6 +73,8 @@
                             | csr_crc16(host->csr.topology_map + 1,
                                         host->selfid_count + 2));
 
+        host->csr.speed_map[1] = 
+                cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1);
         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
                                              | csr_crc16(host->csr.speed_map+1,
                                                          0x3f1));
@@ -71,7 +86,7 @@
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-
+        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -84,13 +99,52 @@
         host->csr.channels_available_lo = ~0;
 }
 
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t size, unsigned char rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        if (rom_version != host->csr.rom_version)
+                 ret = -1;
+        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
+                 ret = -2;
+        else {
+                 memcpy(host->csr.rom,new_rom,size);
+                 host->csr.rom_size=size;
+                 host->csr.rom_version++;
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
+	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        *rom_version=host->csr.rom_version;
+        *rom_size=host->csr.rom_size;
+        if (buffersize < host->csr.rom_size)
+                 ret = -1;
+        else {
+                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
 
 /* Read topology / speed maps and configuration ROM */
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         const char *src;
+        int flags;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
 
         if (csraddr < CSR_TOPOLOGY_MAP) {
                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
@@ -105,6 +159,7 @@
         }
 
         memcpy(buffer, src, length);
+        spin_unlock_irqrestore(&host->csr.lock, flags);
         return RCODE_COMPLETE;
 }
 
@@ -112,7 +167,7 @@
 #define out if (--length == 0) break
 
 static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         int oldcycle;
@@ -222,7 +277,7 @@
 }
 
 static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length)
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         
@@ -302,7 +357,7 @@
 
 
 static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         unsigned long flags;
@@ -379,7 +434,7 @@
 }
 
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, unsigned int length)
+		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
 
@@ -436,9 +491,11 @@
         hpsb_register_addrspace(hl, &map_ops, 
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-        hpsb_register_addrspace(hl, &fcp_ops,
+        if (fcp) {
+		hpsb_register_addrspace(hl, &fcp_ops,
                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
                                 CSR_REGISTER_BASE + CSR_FCP_END);
+	}
         hpsb_register_addrspace(hl, &map_ops,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
diff -urN linux-2.4.21-pre1/drivers/ieee1394/csr.h linux-2.4.21-pre2/drivers/ieee1394/csr.h
--- linux-2.4.21-pre1/drivers/ieee1394/csr.h	Thu Mar  1 16:57:11 2001
+++ linux-2.4.21-pre2/drivers/ieee1394/csr.h	Wed Dec 18 14:16:27 2002
@@ -41,8 +41,10 @@
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
 
-        const quadlet_t *rom;
+        quadlet_t *rom;
         size_t rom_size;
+        unsigned char rom_version;
+
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
diff -urN linux-2.4.21-pre1/drivers/ieee1394/dv1394.c linux-2.4.21-pre2/drivers/ieee1394/dv1394.c
--- linux-2.4.21-pre1/drivers/ieee1394/dv1394.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/dv1394.c	Wed Dec 18 14:16:27 2002
@@ -97,7 +97,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -2587,6 +2586,7 @@
 	return p;
 }
 
+#ifdef CONFIG_DEVFS_FS
 static int dv1394_devfs_add_entry(struct video_card *video)
 {
 	char buf[32];
@@ -2694,6 +2694,7 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS_FS */
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2852,7 +2853,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2874,15 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-	devfs_entry = dv1394_devfs_find("dv");
+{
+	struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
 		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
diff -urN linux-2.4.21-pre1/drivers/ieee1394/eth1394.c linux-2.4.21-pre2/drivers/ieee1394/eth1394.c
--- linux-2.4.21-pre1/drivers/ieee1394/eth1394.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/eth1394.c	Wed Dec 18 14:16:27 2002
@@ -77,7 +77,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -522,7 +522,7 @@
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
 static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len)
+			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
@@ -682,8 +682,8 @@
 	ptask->skb = skb;
 	ptask->addr = addr;
 	ptask->dest_node = dest_node;
-	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
-	schedule_task(&ptask->tq);
+	HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask);
+	hpsb_schedule_work(&ptask->tq);
 
 	return 0;
 fail:
diff -urN linux-2.4.21-pre1/drivers/ieee1394/eth1394.h linux-2.4.21-pre2/drivers/ieee1394/eth1394.h
--- linux-2.4.21-pre1/drivers/ieee1394/eth1394.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/eth1394.h	Wed Dec 18 14:16:27 2002
@@ -56,7 +56,7 @@
 	struct sk_buff *skb;	/* Socket buffer we are sending */
 	nodeid_t dest_node;	/* Destination of the packet */
 	u64 addr;		/* Address */
-	struct tq_struct tq;	/* The task */
+	struct hpsb_queue_struct tq;	/* The task */
 };
 
 /* IP1394 headers */
diff -urN linux-2.4.21-pre1/drivers/ieee1394/highlevel.c linux-2.4.21-pre2/drivers/ieee1394/highlevel.c
--- linux-2.4.21-pre1/drivers/ieee1394/highlevel.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/highlevel.c	Wed Dec 18 14:16:27 2002
@@ -5,6 +5,16 @@
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        unregister address space
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        unregister address space
+ *
  */
 
 #include <linux/config.h>
@@ -129,6 +139,32 @@
         return retval;
 }
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
+{
+        int retval = 0;
+        struct hpsb_address_serve *as;
+        struct list_head *entry;
+
+        write_lock_irq(&addr_space_lock);
+
+        entry = hl->addr_list.next;
+
+        while (entry != &hl->addr_list) {
+                as = list_entry(entry, struct hpsb_address_serve, addr_list);
+                entry = entry->next;
+                if (as->start == start) {
+                        list_del(&as->as_list);
+                        list_del(&as->addr_list);
+                        kfree(as);
+                        retval = 1;
+                        break;
+                }
+        }
+
+        write_unlock_irq(&addr_space_lock);
+
+        return retval;
+}
 
 void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
                          unsigned int channel)
@@ -243,7 +279,7 @@
 }
 
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length)
+                   u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -261,7 +297,7 @@
 
                         if (as->op->read != NULL) {
                                 rcode = as->op->read(host, nodeid, buffer,
-						     addr, partlength);
+						     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,7 +324,7 @@
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length)
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -306,7 +342,7 @@
 
                         if (as->op->write != NULL) {
                                 rcode = as->op->write(host, nodeid, destid,
-						      data, addr, partlength);
+						      data, addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -334,7 +370,7 @@
 
 
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -349,7 +385,7 @@
                 if (as->end > addr) {
                         if (as->op->lock != NULL) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
-                                                     data, arg, ext_tcode);
+                                                     data, arg, ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -367,7 +403,7 @@
 }
 
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -383,7 +419,7 @@
                         if (as->op->lock64 != NULL) {
                                 rcode = as->op->lock64(host, nodeid, store,
                                                        addr, data, arg,
-                                                       ext_tcode);
+                                                       ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -urN linux-2.4.21-pre1/drivers/ieee1394/highlevel.h linux-2.4.21-pre2/drivers/ieee1394/highlevel.h
--- linux-2.4.21-pre1/drivers/ieee1394/highlevel.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/highlevel.h	Wed Dec 18 14:16:27 2002
@@ -74,17 +74,22 @@
          */
 
         /* These functions have to implement block reads for themselves. */
+        /* These functions either return a response code
+           or a negative number. In the first case a response will be generated; in the 
+           later case, no response will be sent and the driver, that handled the request
+           will send the response itself
+        */
         int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length);
+                     u64 addr, unsigned int length, u16 flags);
         int (*write) (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length);
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 
         /* Lock transactions: write results of ext_tcode operation into
          * *store. */
         int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
         int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
-                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 };
 
 
@@ -94,14 +99,23 @@
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
+
+/* these functions are called to handle transactions. They are called, when
+   a packet arrives. The flags argument contains the second word of the first header
+   quadlet of the incoming packet (containing transaction label, retry code,
+   transaction code and priority). These functions either return a response code
+   or a negative number. In the first case a response will be generated; in the 
+   later case, no response will be sent and the driver, that handled the request
+   will send the response itself.
+*/
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length);
+                   u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length);
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
                            unsigned int length);
@@ -130,6 +144,8 @@
 int hpsb_register_addrspace(struct hpsb_highlevel *hl,
                             struct hpsb_address_ops *ops, u64 start, u64 end);
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
+
 /*
  * Enable or disable receving a certain isochronous channel through the
  * iso_receive op.
diff -urN linux-2.4.21-pre1/drivers/ieee1394/hosts.c linux-2.4.21-pre2/drivers/ieee1394/hosts.c
--- linux-2.4.21-pre1/drivers/ieee1394/hosts.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/hosts.c	Wed Dec 18 14:16:27 2002
@@ -138,7 +138,7 @@
 
 	atomic_set(&h->generation, 0);
 
-	INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
+	HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
 
         h->topology_map = h->csr.topology_map + 3;
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
diff -urN linux-2.4.21-pre1/drivers/ieee1394/hosts.h linux-2.4.21-pre2/drivers/ieee1394/hosts.h
--- linux-2.4.21-pre1/drivers/ieee1394/hosts.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/hosts.h	Wed Dec 18 14:16:27 2002
@@ -2,13 +2,20 @@
 #define _IEEE1394_HOSTS_H
 
 #include <linux/wait.h>
-#include <linux/tqueue.h>
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
 #include "ieee1394_types.h"
 #include "csr.h"
 
+/* size of the array used to store config rom (in quadlets)
+   maximum is 0x100. About 0x40 is needed for the default
+   entries. So 0x80 should provide enough space for additional
+   directories etc. 
+   Note: All lowlevel drivers are required to allocate at least
+         this amount of memory for the configuration rom!
+*/
+#define CSR_CONFIG_ROM_SIZE       0x100
 
 struct hpsb_packet;
 
@@ -23,7 +30,7 @@
 
         struct list_head pending_packets;
         spinlock_t pending_pkt_lock;
-        struct tq_struct timeout_tq;
+        struct hpsb_queue_struct timeout_tq;
 
         /* A bitmask where a set bit means that this tlabel is in use.
          * FIXME - should be handled per node instead of per bus. */
@@ -119,7 +126,7 @@
          * may not fail.  If any allocation is required, it must be done
          * earlier.
          */
-        size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
+        size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
 
         /* This function shall implement packet transmission based on
          * packet->type.  It shall CRC both parts of the packet (unless
@@ -172,4 +179,24 @@
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
 
+/* updates the configuration rom of a host.
+ * rom_version must be the current version,
+ * otherwise it will fail with return value -1.
+ * Return value -2 indicates that the new
+ * rom version is too big.
+ * Return value 0 indicates success
+ */
+int hpsb_update_config_rom(struct hpsb_host *host,
+      const quadlet_t *new_rom, size_t size, unsigned char rom_version);
+
+/* reads the current version of the configuration rom of a host.
+ * buffersize is the size of the buffer, rom_size
+ * returns the size of the current rom image.
+ * rom_version is the version number of the fetched rom.
+ * return value -1 indicates, that the buffer was
+ * too small, 0 indicates success.
+ */
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
+      size_t buffersize, size_t *rom_size, unsigned char *rom_version);
+
 #endif /* _IEEE1394_HOSTS_H */
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ieee1394_core.c linux-2.4.21-pre2/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.21-pre1/drivers/ieee1394/ieee1394_core.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ieee1394_core.c	Wed Dec 18 14:16:27 2002
@@ -5,9 +5,19 @@
  *               highlevel or lowlevel code
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        loopback functionality in hpsb_send_packet
+ *        allow highlevel drivers to disable automatic response generation
+ *              and to generate responses themselves (deferred)
+ *
  */
 
 #include <linux/config.h>
@@ -19,7 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
@@ -72,9 +81,10 @@
 	struct list_head *lh, *next;
 
 	list_for_each_safe(lh, next, &packet->complete_tq) {
-		struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
-		list_del(&tq->list);
-		schedule_task(tq);
+		struct hpsb_queue_struct *tq =
+			list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list);
+		list_del(&tq->hpsb_queue_list);
+		hpsb_schedule_work(tq);
 	}
 
 	return;
@@ -83,11 +93,11 @@
 /**
  * hpsb_add_packet_complete_task - add a new task for when a packet completes
  * @packet: the packet whose completion we want the task added to
- * @tq: the tq_struct describing the task to add
+ * @tq: the hpsb_queue_struct describing the task to add
  */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq)
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq)
 {
-	list_add_tail(&tq->list, &packet->complete_tq);
+	list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq);
 	return;
 }
 
@@ -372,12 +382,19 @@
                 build_speed_map(host, host->node_count);
         }
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+        HPSB_INFO("selfid_complete called with successful SelfID stage "
+		"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
+#endif
         /* irm_id is kept up to date by check_selfids() */
         if (host->irm_id == host->node_id) {
                 host->is_irm = 1;
                 host->is_busmgr = 1;
                 host->busmgr_id = host->node_id;
                 host->csr.bus_manager_id = host->node_id;
+        } else {
+                host->is_busmgr = 0;
+                host->is_irm = 0;
         }
 
         host->reset_retries = 0;
@@ -420,7 +437,7 @@
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         up(&packet->state_change);
-        schedule_task(&host->timeout_tq);
+        hpsb_schedule_work(&host->timeout_tq);
 }
 
 /**
@@ -448,6 +465,45 @@
 
         packet->state = hpsb_queued;
 
+        if (packet->node_id == host->node_id)
+        { /* it is a local request, so handle it locally */
+                quadlet_t *data;
+                size_t size=packet->data_size+packet->header_size;
+
+                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                if (!data) {
+                        HPSB_ERR("unable to allocate memory for concatenating header and data");
+                        return 0;
+                }
+
+                memcpy(data, packet->header, packet->header_size);
+
+                if (packet->data_size)
+                {
+                        if (packet->data_be) {
+                                memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
+                        } else {
+                                int i;
+                                quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size);
+                                for (i=0; i < packet->data_size/4; i++) {
+                                        my_data[i] = cpu_to_be32(packet->data[i]);
+                                }
+                        }
+                }
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                dump_packet("send packet local:", packet->header,
+                            packet->header_size);
+#endif
+                hpsb_packet_sent(host, packet,  packet->expect_response?ACK_PENDING:ACK_COMPLETE);
+                hpsb_packet_received(host, data, size, 0);
+
+                kfree(data);
+
+                return 1;
+        }
+
         if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
                 packet->speed_code =
                         host->speed_map[(host->node_id & NODE_MASK) * 64
@@ -600,8 +656,10 @@
 {
         struct hpsb_packet *packet;
         int length, rcode, extcode;
+        quadlet_t buffer;
         nodeid_t source = data[1] >> 16;
-	nodeid_t dest = data[0] >> 16;
+        nodeid_t dest = data[0] >> 16;
+        u16 flags = (u16) data[0];
         u64 addr;
 
         /* big FIXME - no error checking is done for an out of bounds length */
@@ -610,10 +668,11 @@
         case TCODE_WRITEQ:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+3,
-					addr, 4);
+					addr, 4, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -624,10 +683,11 @@
         case TCODE_WRITEB:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+4,
-					addr, data[3]>>16);
+					addr, data[3]>>16, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -636,12 +696,14 @@
                 break;
 
         case TCODE_READQ:
-                PREP_REPLY_PACKET(0);
-
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-                rcode = highlevel_read(host, source, data, addr, 4);
-                fill_async_readquad_resp(packet, rcode, *data);
-                send_packet_nocare(packet);
+                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+
+                if (rcode >= 0) {
+                        PREP_REPLY_PACKET(0);
+                        fill_async_readquad_resp(packet, rcode, buffer);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_READB:
@@ -650,9 +712,12 @@
 
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_read(host, source, packet->data, addr,
-                                       length);
-                fill_async_readblock_resp(packet, rcode, length);
-                send_packet_nocare(packet);
+                                       length, flags);
+
+                if (rcode >= 0) {
+                        fill_async_readblock_resp(packet, rcode, length);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_LOCK_REQUEST:
@@ -670,7 +735,7 @@
                 switch (length) {
                 case 4:
                         rcode = highlevel_lock(host, source, packet->data, addr,
-                                               data[4], 0, extcode);
+                                               data[4], 0, extcode,flags);
                         fill_async_lock_resp(packet, rcode, extcode, 4);
                         break;
                 case 8:
@@ -679,13 +744,13 @@
                                 rcode = highlevel_lock(host, source,
                                                        packet->data, addr,
                                                        data[5], data[4], 
-                                                       extcode);
+                                                       extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 4);
                         } else {
                                 rcode = highlevel_lock64(host, source,
                                              (octlet_t *)packet->data, addr,
                                              *(octlet_t *)(data + 4), 0ULL,
-                                             extcode);
+                                             extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 8);
                         }
                         break;
@@ -694,15 +759,20 @@
                                                  (octlet_t *)packet->data, addr,
                                                  *(octlet_t *)(data + 6),
                                                  *(octlet_t *)(data + 4), 
-                                                 extcode);
+                                                 extcode, flags);
                         fill_async_lock_resp(packet, rcode, extcode, 8);
                         break;
                 default:
-                        fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
+                        rcode = RCODE_TYPE_ERROR;
+                        fill_async_lock_resp(packet, rcode,
                                              extcode, 0);
                 }
 
-                send_packet_nocare(packet);
+                if (rcode >= 0) {
+                        send_packet_nocare(packet);
+                } else {
+                        free_hpsb_packet(packet);
+                }
                 break;
         }
 
@@ -811,7 +881,7 @@
         }
 
         if (!list_empty(&host->pending_packets))
-		schedule_task(&host->timeout_tq);
+		hpsb_schedule_work(&host->timeout_tq);
 
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
@@ -1109,6 +1179,7 @@
 EXPORT_SYMBOL(hpsb_make_writeqpacket);
 EXPORT_SYMBOL(hpsb_make_writebpacket);
 EXPORT_SYMBOL(hpsb_make_lockpacket);
+EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_packet_success);
 EXPORT_SYMBOL(hpsb_make_packet);
@@ -1119,6 +1190,7 @@
 EXPORT_SYMBOL(hpsb_register_highlevel);
 EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_unregister_addrspace);
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(highlevel_read);
@@ -1135,6 +1207,8 @@
 EXPORT_SYMBOL(hpsb_node_read);
 EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(hpsb_node_lock);
+EXPORT_SYMBOL(hpsb_update_config_rom);
+EXPORT_SYMBOL(hpsb_get_config_rom);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ieee1394_core.h linux-2.4.21-pre2/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.21-pre1/drivers/ieee1394/ieee1394_core.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ieee1394_core.h	Wed Dec 18 14:16:27 2002
@@ -2,7 +2,6 @@
 #ifndef _IEEE1394_CORE_H
 #define _IEEE1394_CORE_H
 
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/proc_fs.h>
@@ -78,7 +77,7 @@
 };
 
 /* add a new task for when a packet completes */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq);
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq);
 
 static inline struct hpsb_packet *driver_packet(struct list_head *l)
 {
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ieee1394_transactions.c linux-2.4.21-pre2/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.21-pre1/drivers/ieee1394/ieee1394_transactions.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ieee1394_transactions.c	Wed Dec 18 14:16:27 2002
@@ -297,14 +297,6 @@
         HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
-
-int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, 
-                       quadlet_t *buffer, size_t length)
-{
-        if (host->node_id != node) return -1;
-        return highlevel_read(host, node, buffer, addr, length);
-}
-
 struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
                                           u64 addr)
 {
@@ -400,6 +392,31 @@
         return p;
 }
 
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                           u64 addr, int extcode)
+{
+        struct hpsb_packet *p;
+
+        p = alloc_hpsb_packet(16);
+        if (!p) return NULL;
+
+        p->host = host;
+        p->tlabel = get_tlabel(host, node, 1);
+        p->node_id = node;
+
+        switch (extcode) {
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                fill_async_lock(p, addr, extcode, 8);
+                break;
+        default:
+                fill_async_lock(p, addr, extcode, 16);
+                break;
+        }
+
+        return p;
+}
+
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) 
 {
@@ -429,18 +446,6 @@
                 return -EINVAL;
         }
 
-        if (host->node_id == node) {
-                switch(highlevel_read(host, node, buffer, addr, length)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         if (length == 4) {
                 packet = hpsb_make_readqpacket(host, node, addr);
         } else {
@@ -509,18 +514,6 @@
 	if (length == 0)
 		return -EINVAL;
 
-	if (host->node_id == node) {
-		switch(highlevel_write(host, node, node, buffer, addr, length)) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-		default:
-			return -EINVAL;
-		}
-	}
-
 	packet = hpsb_make_packet (host, node, addr, buffer, length);
 
 	if (!packet)
@@ -551,19 +544,6 @@
         struct hpsb_packet *packet;
         int retval = 0, length;
         
-        if (host->node_id == node) {
-                switch(highlevel_lock(host, node, data, addr, *data, arg,
-                                      extcode)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         packet = alloc_hpsb_packet(8);
         if (!packet) {
                 return -ENOMEM;
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ieee1394_transactions.h linux-2.4.21-pre2/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.4.21-pre1/drivers/ieee1394/ieee1394_transactions.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ieee1394_transactions.h	Wed Dec 18 14:16:27 2002
@@ -42,6 +42,8 @@
                                            size_t length);
 struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
                                          u64 addr, int extcode);
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                          u64 addr, int extcode);
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) ;
 
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ieee1394_types.h linux-2.4.21-pre2/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.21-pre1/drivers/ieee1394/ieee1394_types.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ieee1394_types.h	Wed Dec 18 14:16:27 2002
@@ -20,23 +20,6 @@
 #define __devexit_p(x) x
 #endif
 
-/* This showed up around this time */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
-
-# ifndef MODULE_LICENSE
-# define MODULE_LICENSE(x)
-# endif
-
-# ifndef min
-# define min(x,y) ({ \
-	const typeof(x) _x = (x);       \
-	const typeof(y) _y = (y);       \
-	(void) (&_x == &_y);            \
-	_x < _y ? _x : _y; })
-# endif
-
-#endif /* Linux version < 2.4.12 */
-
 #include <linux/spinlock.h>
 
 #ifndef list_for_each_safe
@@ -46,9 +29,7 @@
 
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
 #define pte_offset_kernel pte_offset
-#endif
 
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -58,10 +39,24 @@
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
+
+/* Use task queue */
+#include <linux/tqueue.h>
+#define hpsb_queue_struct tq_struct
+#define hpsb_queue_list list
+#define hpsb_schedule_work(x) schedule_task(x)
+#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
+#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z)
+
+
 typedef u32 quadlet_t;
 typedef u64 octlet_t;
 typedef u16 nodeid_t;
 
+typedef u8  byte_t;
+typedef u64 nodeaddr_t;
+typedef u16 arm_length_t;
+
 #define BUS_MASK  0xffc0
 #define NODE_MASK 0x003f
 #define LOCAL_BUS 0xffc0
diff -urN linux-2.4.21-pre1/drivers/ieee1394/ohci1394.c linux-2.4.21-pre2/drivers/ieee1394/ohci1394.c
--- linux-2.4.21-pre1/drivers/ieee1394/ohci1394.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/ohci1394.c	Wed Dec 18 14:16:27 2002
@@ -91,7 +91,6 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 
@@ -154,7 +153,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 693 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -1174,74 +1173,60 @@
 	}
 	if (event & OHCI1394_selfIDComplete) {
 		if (host->in_bus_reset) {
-			node_id = reg_read(ohci, OHCI1394_NodeID); 
+			node_id = reg_read(ohci, OHCI1394_NodeID);
 
-			/* If our nodeid is not valid, give a msec delay
-			 * to let it settle in and try again.  */
 			if (!(node_id & 0x80000000)) {
-				mdelay(1);
-				node_id = reg_read(ohci, OHCI1394_NodeID);
+				PRINT(KERN_ERR, ohci->id,
+				      "SelfID received, but NodeID invalid "
+				      "(probably new bus reset occured): %08X",
+				      node_id);
+				goto selfid_not_valid;
 			}
 
-			if (node_id & 0x80000000) { /* NodeID valid */
-				phyid =  node_id & 0x0000003f;
-				isroot = (node_id & 0x40000000) != 0;
-
-				DBGMSG(ohci->id,
-				      "SelfID interrupt received "
-				      "(phyid %d, %s)", phyid, 
-				      (isroot ? "root" : "not root"));
+			phyid =  node_id & 0x0000003f;
+			isroot = (node_id & 0x40000000) != 0;
+
+			DBGMSG(ohci->id,
+			       "SelfID interrupt received "
+			       "(phyid %d, %s)", phyid,
+			       (isroot ? "root" : "not root"));
+
+			handle_selfid(ohci, host, phyid, isroot);
+
+			/* Clear the bus reset event and re-enable the
+			 * busReset interrupt.  */
+			spin_lock_irqsave(&ohci->event_lock, flags);
+			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+			reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
+			spin_unlock_irqrestore(&ohci->event_lock, flags);
+
+			/* Accept Physical requests from all nodes. */
+			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
+			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
 
-				handle_selfid(ohci, host, 
-					      phyid, isroot);
+			/* Turn on phys dma reception.
+			 *
+			 * TODO: Enable some sort of filtering management.
+			 */
+			if (phys_dma) {
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000);
 			} else {
-				PRINT(KERN_ERR, ohci->id, 
-				      "SelfID interrupt received, but "
-				      "NodeID is not valid: %08X",
-				      node_id);
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
 			}
+			DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
+			       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
+			       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
 
-			/* Accept Physical requests from all nodes. */
-			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
-				  0xffffffff);
+			hpsb_selfid_complete(host, phyid, isroot);
 		} else
-			PRINT(KERN_ERR, ohci->id, 
+			PRINT(KERN_ERR, ohci->id,
 			      "SelfID received outside of bus reset sequence");
 
-		/* Finally, we clear the busReset event and reenable
-		 * the busReset interrupt. */
-		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
-		spin_unlock_irqrestore(&ohci->event_lock, flags);
-		event &= ~OHCI1394_selfIDComplete;	
-
-		/* Turn on phys dma reception. We should
-		 * probably manage the filtering somehow, 
-		 * instead of blindly turning it on.  */
-
-		/*
-		 * CAUTION!
-		 * Some chips (TI TSB43AB22) won't take a value in
-		 * the PhyReqFilter register until after the IntEvent
-		 * is cleared for bus reset, and even then a short
-		 * delay is required.
-		 */
-		if (phys_dma) {
-			mdelay(1);
-			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyUpperBound,
-				  0xffff0000);
-		}
-
-		DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
-		       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
-		       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
+		event &= ~OHCI1394_selfIDComplete;
+selfid_not_valid:
 	}
 
 	/* Make sure we handle everything, just in case we accidentally
@@ -1905,7 +1890,7 @@
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
-static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
 	struct ti_ohci *ohci=host->hostdata;
 
diff -urN linux-2.4.21-pre1/drivers/ieee1394/pcilynx.c linux-2.4.21-pre2/drivers/ieee1394/pcilynx.c
--- linux-2.4.21-pre1/drivers/ieee1394/pcilynx.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/pcilynx.c	Wed Dec 18 14:16:27 2002
@@ -1677,7 +1677,7 @@
 
 
 
-static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
         struct ti_lynx *lynx = host->hostdata;
         *ptr = lynx->config_rom;
diff -urN linux-2.4.21-pre1/drivers/ieee1394/raw1394.c linux-2.4.21-pre2/drivers/ieee1394/raw1394.c
--- linux-2.4.21-pre1/drivers/ieee1394/raw1394.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/raw1394.c	Wed Dec 18 14:16:27 2002
@@ -4,9 +4,27 @@
  * Raw interface to the bus
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *                     2002 Christian Toegel <christian.toegel@gmx.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *        address range mapping
+ *        adaptation for new (transparent) loopback mechanism
+ *        sending of arbitrary async packets
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        address range mapping
+ *        lock64 request
+ *        transmit physical packet
+ *        busreset notification control (switch on/off)
+ *        busreset with selection of type (short/long)
+ *        request_reply
  */
 
 #include <linux/kernel.h>
@@ -40,6 +58,16 @@
 #define ptr2int(x) ((u64)(u32)x)
 #endif
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define RAW1394_DEBUG
+#endif
+
+#ifdef RAW1394_DEBUG
+#define DBGMSG(fmt, args...) \
+printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
+#else
+#define DBGMSG(fmt, args...)
+#endif
 
 static devfs_handle_t devfs_handle;
 
@@ -53,6 +81,21 @@
 static atomic_t iso_buffer_size;
 static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
 
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags);
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+static struct hpsb_address_ops arm_ops = {
+        read:     arm_read,
+        write:    arm_write,
+        lock:     arm_lock,
+        lock64:   arm_lock64,
+};
+
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
@@ -64,7 +107,7 @@
         if (req != NULL) {
                 memset(req, 0, sizeof(struct pending_request));
                 INIT_LIST_HEAD(&req->list);
-		INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
+                HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
         }
 
         return req;
@@ -128,7 +171,11 @@
                 req->req.length = 0;
         }
 
-        free_tlabel(packet->host, packet->node_id, packet->tlabel);
+	if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
+	    (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
+	    (req->req.type == RAW1394_REQ_LOCK) ||
+	    (req->req.type == RAW1394_REQ_LOCK64))
+                free_tlabel(packet->host, packet->node_id, packet->tlabel);
 
         queue_complete_req(req);
 }
@@ -137,6 +184,7 @@
 static void add_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
         hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
         if (hi != NULL) {
@@ -144,10 +192,10 @@
                 hi->host = host;
                 INIT_LIST_HEAD(&hi->file_info_list);
 
-                spin_lock_irq(&host_info_lock);
+                spin_lock_irqsave(&host_info_lock, flags);
                 list_add_tail(&hi->list, &host_info_list);
                 host_count++;
-                spin_unlock_irq(&host_info_lock);
+                spin_unlock_irqrestore(&host_info_lock, flags);
         }
 
         atomic_inc(&internal_generation);
@@ -172,15 +220,22 @@
 static void remove_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
-        spin_lock_irq(&host_info_lock);
+        spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(host);
 
         if (hi != NULL) {
                 list_del(&hi->list);
                 host_count--;
+                /* 
+                   FIXME: adressranges should be removed 
+                   and fileinfo states should be initialized
+                   (including setting generation to 
+                   internal-generation ...)
+                */
         }
-        spin_unlock_irq(&host_info_lock);
+        spin_unlock_irqrestore(&host_info_lock, flags);
 
         if (hi == NULL) {
                 printk(KERN_ERR "raw1394: attempt to remove unknown host "
@@ -207,20 +262,22 @@
         if (hi != NULL) {
                 list_for_each(lh, &hi->file_info_list) {
                         fi = list_entry(lh, struct file_info, list);
-                        req = __alloc_pending_request(SLAB_ATOMIC);
+                        if (fi->notification == RAW1394_NOTIFY_ON) {
+                                req = __alloc_pending_request(SLAB_ATOMIC);
 
-                        if (req != NULL) {
-                                req->file_info = fi;
-                                req->req.type = RAW1394_REQ_BUS_RESET;
-                                req->req.generation = get_hpsb_generation(host);
-                                req->req.misc = (host->node_id << 16)
-                                        | host->node_count;
-                                if (fi->protocol_version > 3) {
-                                        req->req.misc |= ((host->irm_id
-                                                           & NODE_MASK) << 8);
-                                }
+                                if (req != NULL) {
+                                        req->file_info = fi;
+                                        req->req.type = RAW1394_REQ_BUS_RESET;
+                                        req->req.generation = get_hpsb_generation(host);
+                                        req->req.misc = (host->node_id << 16)
+                                                | host->node_count;
+                                        if (fi->protocol_version > 3) {
+                                                req->req.misc |= ((host->irm_id
+                                                                   & NODE_MASK) << 8);
+                                        }
 
-                                queue_complete_req(req);
+                                        queue_complete_req(req);
+                                }
                         }
                 }
         }
@@ -529,7 +586,7 @@
 {
         int channel = req->req.misc;
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         if ((channel > 63) || (channel < -64)) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
         } else if (channel >= 0) {
@@ -556,7 +613,7 @@
 
         req->req.length = 0;
         queue_complete_req(req);
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
@@ -579,84 +636,9 @@
         queue_complete_req(req);
 }
 
-static int handle_local_request(struct file_info *fi,
-                                struct pending_request *req, int node)
-{
-        u64 addr = req->req.address & 0xffffffffffffULL;
-
-        req->data = kmalloc(req->req.length, SLAB_KERNEL);
-        if (!req->data) return -ENOMEM;
-        req->free_data = 1;
-
-        switch (req->req.type) {
-        case RAW1394_REQ_ASYNC_READ:
-                req->req.error = highlevel_read(fi->host, node, req->data, addr,
-                                                req->req.length);
-                break;
-
-        case RAW1394_REQ_ASYNC_WRITE:
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->req.error = highlevel_write(fi->host, node, node, req->data,
-                                                 addr, req->req.length);
-                req->req.length = 0;
-                break;
 
-        case RAW1394_REQ_LOCK:
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 4) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                if (req->req.length == 8) {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[1],
-                                                        req->data[0],
-                                                        req->req.misc);
-                        req->req.length = 4;
-                } else {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[0], 0,
-                                                        req->req.misc);
-                }
-                break;
-
-        case RAW1394_REQ_LOCK64:
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        if (req->req.error)
-                req->req.length = 0;
-        if (req->req.error >= 0)
-                req->req.error |= ACK_PENDING << 16;
-
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
-}
-
-static int handle_remote_request(struct file_info *fi,
-                                 struct pending_request *req, int node)
+static int handle_async_request(struct file_info *fi,
+                                struct pending_request *req, int node)
 {
         struct hpsb_packet *packet = NULL;
         u64 addr = req->req.address & 0xffffffffffffULL;
@@ -664,11 +646,13 @@
         switch (req->req.type) {
         case RAW1394_REQ_ASYNC_READ:
                 if (req->req.length == 4) {
+                        DBGMSG("quadlet_read_request called");        
                         packet = hpsb_make_readqpacket(fi->host, node, addr);
                         if (!packet) return -ENOMEM;
 
                         req->data = &packet->header[3];
                 } else {
+                        DBGMSG("block_read_request called");
                         packet = hpsb_make_readbpacket(fi->host, node, addr,
                                                        req->req.length);
                         if (!packet) return -ENOMEM;
@@ -681,6 +665,7 @@
                 if (req->req.length == 4) {
                         quadlet_t x;
 
+                        DBGMSG("quadlet_write_request called");
                         if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) {
                                 req->req.error = RAW1394_ERROR_MEMFAULT;
                         }
@@ -689,6 +674,7 @@
                                                         x);
                         if (!packet) return -ENOMEM;
                 } else {
+                        DBGMSG("block_write_request called");
                         packet = hpsb_make_writebpacket(fi->host, node, addr,
                                                         req->req.length);
                         if (!packet) return -ENOMEM;
@@ -702,6 +688,7 @@
                 break;
 
         case RAW1394_REQ_LOCK:
+                DBGMSG("lock_request called");
                 if ((req->req.misc == EXTCODE_FETCH_ADD)
                     || (req->req.misc == EXTCODE_LITTLE_ADD)) {
                         if (req->req.length != 4) {
@@ -730,6 +717,33 @@
                 break;
 
         case RAW1394_REQ_LOCK64:
+                DBGMSG("lock64_request called");
+                if ((req->req.misc == EXTCODE_FETCH_ADD)
+                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+                        if (req->req.length != 8) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                } else {
+                        if (req->req.length != 16) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                }
+                packet = hpsb_make_lock64packet(fi->host, node, addr,
+                                                req->req.misc);
+                if (!packet) return -ENOMEM;
+
+                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+                                   req->req.length)) {
+                        req->req.error = RAW1394_ERROR_MEMFAULT;
+                        break;
+                }
+
+                req->data = packet->data;
+                req->req.length = 8;
+                break;
+
         default:
                 req->req.error = RAW1394_ERROR_STATE_ORDER;
         }
@@ -783,8 +797,7 @@
                 return sizeof(struct raw1394_request);
         }
 
-        req->tq.data = req;
-        req->tq.routine = (void (*)(void*))queue_complete_req;
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
         req->req.length = 0;
 	hpsb_add_packet_complete_task(packet, &req->tq);
 
@@ -803,25 +816,1092 @@
         return sizeof(struct raw1394_request);
 }
 
-static int state_connected(struct file_info *fi, struct pending_request *req)
+static int handle_async_send(struct file_info *fi, struct pending_request *req)
 {
-        int node = req->req.address >> 48;
+        struct hpsb_packet *packet;
+        int header_length = req->req.misc & 0xffff;
+        int expect_response = req->req.misc >> 16;
 
-        req->req.error = RAW1394_ERROR_NONE;
+        if ((header_length > req->req.length) ||
+            (header_length  < 12))
+        {
+                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+        } 
 
-        if (req->req.type ==  RAW1394_REQ_ISO_SEND) {
-                return handle_iso_send(fi, req, node);
+        packet = alloc_hpsb_packet(req->req.length-header_length);
+        req->packet = packet;
+        if (!packet) return -ENOMEM;
+
+        if (copy_from_user(packet->header, int2ptr(req->req.sendb),
+                           header_length)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
         }
 
-        if (req->req.generation != get_hpsb_generation(fi->host)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = get_hpsb_generation(fi->host);
+        if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length,
+                           packet->data_size)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
                 req->req.length = 0;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        packet->type = hpsb_async;
+        packet->node_id = packet->header[0] >> 16;
+        packet->tcode = (packet->header[0] >> 4) & 0xf;
+        packet->tlabel = (packet->header[0] >> 10) &0x3f;
+        packet->host = fi->host;
+        packet->expect_response = expect_response;
+        packet->header_size=header_length;
+        packet->data_size=req->req.length-header_length;
+
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
+        req->req.length = 0;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+
+        /* Update the generation of the packet just before sending. */
+        packet->generation = get_hpsb_generation(fi->host);
+
+        if (!hpsb_send_packet(packet)) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                queue_complete_req(req);
+        }
+
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_read  called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_read addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_read blocklength too big -> rcode_data_error");
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_READ) {
+                        if (!(arm_addr->client_transactions & ARM_READ)) {
+                                memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                       length);
+                                DBGMSG("arm_read -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_read -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_READ) {
+                DBGMSG("arm_read -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                length * sizeof(byte_t) +
+                                sizeof (struct arm_request_response);
+                } else {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                sizeof (struct arm_request_response);
+                }
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer  = NULL;
+                arm_resp->buffer = NULL;
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer = ((byte_t *)(arm_resp) + 
+                                (sizeof(struct arm_response)));
+                        memcpy (arm_resp->buffer,
+                                (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                length);
+                        arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                                sizeof (struct arm_request_response) +
+                                sizeof (struct arm_request) +
+                                sizeof (struct arm_response));
+                }
+                arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0;
+                arm_resp->response_code = rcode;
+                arm_req->buffer_length = 0;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1, length_conflict=0;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_write called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_write addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_write blocklength too big -> rcode_data_error");
+                length_conflict = 1;
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_WRITE) {
+                        if (!(arm_addr->client_transactions & ARM_WRITE)) {
+                                memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        data, length);
+                                DBGMSG("arm_write -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_write -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_WRITE) {
+                DBGMSG("arm_write -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request my be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        (length) * sizeof(byte_t) +
+                        sizeof (struct arm_request_response);
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = NULL;
+                memcpy (arm_req->buffer, data, length);
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_req->buffer_length = length;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = destid;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->buffer_length = 0;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1;
+        quadlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data));
+        } else {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                printk(KERN_ERR "raw1394: arm_lock FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                }
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) + 
+                        sizeof (struct arm_request_response);  /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        octlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
+        } else {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
+                      "%8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
+                      (u32) ((be64_to_cpu(arg)  >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(arg)  & 0xFFFFFFFF));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search addressentry in file_info's for host */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock64 addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                printk(KERN_ERR "raw1394: arm_lock64 FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock64 -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                } 
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock64 -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock64 -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) +
+                        sizeof (struct arm_request_response); /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_register(struct file_info *fi, struct pending_request *req)
+{
+        int retval;
+        struct arm_addr *addr;
+        struct list_head *lh, *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        int same_host, another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_register called "
+              "addr(Offset): %8.8x %8.8x length: %u "
+              "rights: %2.2X notify: %2.2X "
+              "max_blk_len: %4.4X",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF),
+              req->req.length, ((req->req.misc >> 8) & 0xFF),
+              (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF));
+        /* check addressrange */
+        if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) ||
+                (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) {
+                req->req.length = 0;
+                return (-EINVAL);
+        }
+        /* addr-list-entry for fileinfo */
+        addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); 
+        if (!addr) {
+                req->req.length = 0;
+                return (-ENOMEM);
+        } 
+        /* allocation of addr_space_buffer */
+        addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL);
+        if (!(addr->addr_space_buffer)) {
+                kfree(addr);
+                req->req.length = 0;
+                return (-ENOMEM);
+        }
+        /* initialization of addr_space_buffer */
+        if ((req->req.sendb)== (unsigned long)NULL) {
+                /* init: set 0 */
+                memset(addr->addr_space_buffer, 0,req->req.length);
+        } else {
+                /* init: user -> kernel */
+                if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb),
+                        req->req.length)) {
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        return (-EFAULT);
+                }
+        }
+        INIT_LIST_HEAD(&addr->addr_list);
+        addr->arm_tag   = req->req.tag;
+        addr->start     = req->req.address;
+        addr->end       = req->req.address + req->req.length;
+        addr->access_rights = (u8) (req->req.misc & 0x0F);
+        addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
+        addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
+        addr->access_rights |= addr->client_transactions;
+        addr->notification_options |= addr->client_transactions;
+        addr->recvb     = req->req.recvb;
+        addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+        spin_lock_irqsave(&host_info_lock, flags);
+        hi = find_host_info(fi->host);
+        same_host = 0;
+        another_host = 0;
+        /* same host with address-entry containing same addressrange ? */
+        list_for_each(lh, &hi->file_info_list) {
+                fi_hlp = list_entry(lh, struct file_info, list);
+                entry = fi_hlp->addr_list.next;
+                while (entry != &(fi_hlp->addr_list)) {
+                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                        if ( (arm_addr->start == addr->start) && 
+                                (arm_addr->end == addr->end)) {
+                                DBGMSG("same host ownes same "
+                                        "addressrange -> EALREADY");
+                                same_host = 1;
+                                break;
+                        }
+                        entry = entry->next;
+                }
+                if (same_host) {
+                        break;
+                }
+        }
+        if (same_host) {
+                /* addressrange occupied by same host */
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY);
+        }
+        /* another host with valid address-entry containing same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                        if ( (arm_addr->start == addr->start) && 
+                                                (arm_addr->end == addr->end)) {
+                                                DBGMSG("another host ownes same "
+                                                "addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("another hosts entry is valid -> SUCCESS");
+                if (copy_to_user(int2ptr(req->req.recvb),
+                        int2ptr(&addr->start),sizeof(u64))) {
+                        printk(KERN_ERR "raw1394: arm_register failed "
+                              " address-range-entry is invalid -> EFAULT !!!\n");
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        spin_unlock_irqrestore(&host_info_lock, flags);
+                        return (-EFAULT);
+                }
+                free_pending_request(req); /* immediate success or fail */
+                /* INSERT ENTRY */
+                list_add_tail(&addr->addr_list, &fi->addr_list);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        }
+        retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address,
+                req->req.address + req->req.length);
+        if (retval) {
+               /* INSERT ENTRY */
+               list_add_tail(&addr->addr_list, &fi->addr_list);
+        } else {
+                DBGMSG("arm_register failed errno: %d \n",retval);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY); 
+        }
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_unregister(struct file_info *fi, struct pending_request *req)
+{
+        int found  = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_Unregister called addr(Offset): "
+              "%8.8x %8.8x",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF));
+        spin_lock_irqsave(&host_info_lock, flags);
+        /* get addr */
+        entry = fi->addr_list.next;
+        while (entry != &(fi->addr_list)) {
+                addr = list_entry(entry, struct arm_addr, addr_list);
+                if (addr->start == req->req.address) {
+                        found = 1;
+                        break;
+                }
+                entry = entry->next;
+        }
+        if (!found) {
+                DBGMSG("arm_Unregister addr not found");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("arm_Unregister addr found");
+        another_host = 0;
+        /* another host with valid address-entry containing 
+           same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, 
+                                                struct arm_addr, addr_list);
+                                        if (arm_addr->start == 
+                                                addr->start) {
+                                                DBGMSG("another host ownes "
+                                                "same addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("delete entry from list -> success");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                free_pending_request(req); /* immediate success or fail */
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        } 
+        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+        if (!retval) {
+                printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("delete entry from list -> success");
+        list_del(&addr->addr_list);
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        kfree(addr->addr_space_buffer);
+        kfree(addr);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int reset_notification(struct file_info *fi, struct pending_request *req)
+{
+        DBGMSG("reset_notification called - switch %s ",
+                (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON");
+        if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
+                (req->req.misc == RAW1394_NOTIFY_ON)) {
+                fi->notification=(u8)req->req.misc;
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                return sizeof(struct raw1394_request);
+        } 
+        /* error EINVAL (22) invalid argument */
+        return (-EINVAL);
+}
+
+static int write_phypacket(struct file_info *fi, struct pending_request *req)
+{
+        struct hpsb_packet *packet = NULL;
+        int retval=0;
+        quadlet_t data;
+
+        data = be32_to_cpu((u32)req->req.sendb);
+        DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data);
+        packet = hpsb_make_phypacket (fi->host, data);
+        if (!packet) return -ENOMEM;
+        req->req.length=0;
+        req->packet=packet;
+        req->tq.data=req;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+        packet->generation = req->req.generation;
+        retval = hpsb_send_packet(packet);
+        DBGMSG("write_phypacket send_packet called => retval: %d ",
+                retval);
+        if (! retval) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                req->req.length = 0;
+                queue_complete_req(req);
+        }
+        return sizeof(struct raw1394_request);
+}
+
+static int get_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        size_t return_size;
+        unsigned char rom_version;
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        int status;
+        if (!data) return -ENOMEM;
+        status = hpsb_get_config_rom(fi->host, data, 
+                req->req.length, &return_size, &rom_version);
+        if (copy_to_user(int2ptr(req->req.recvb), data, 
+                req->req.length))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.tag), &return_size, 
+                sizeof(return_size)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.address), &rom_version, 
+                sizeof(rom_version)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.sendb), &status, 
+                sizeof(status)))
+                ret = -EFAULT;
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int update_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        if (!data) return -ENOMEM;
+        if (copy_from_user(data,int2ptr(req->req.sendb), 
+                req->req.length)) {
+                ret= -EFAULT;
+        } else {
+                int status = hpsb_update_config_rom(fi->host, 
+                        data, req->req.length, 
+                        (unsigned char) req->req.misc);
+                if (copy_to_user(int2ptr(req->req.recvb), 
+                        &status, sizeof(status)))
+                        ret = -ENOMEM;
+        }
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int state_connected(struct file_info *fi, struct pending_request *req)
+{
+        int node = req->req.address >> 48;
+
+        req->req.error = RAW1394_ERROR_NONE;
+
         switch (req->req.type) {
+
+        case RAW1394_REQ_ECHO:
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+
+        case RAW1394_REQ_ISO_SEND:
+                return handle_iso_send(fi, req, node);
+
+        case RAW1394_REQ_ARM_REGISTER:
+                return arm_register(fi, req);
+
+        case RAW1394_REQ_ARM_UNREGISTER:
+                return arm_unregister(fi, req);
+
+        case RAW1394_REQ_RESET_NOTIFY:
+                return reset_notification(fi, req);
+
         case RAW1394_REQ_ISO_LISTEN:
                 handle_iso_listen(fi, req);
                 return sizeof(struct raw1394_request);
@@ -831,21 +1911,49 @@
                 return sizeof(struct raw1394_request);
 
         case RAW1394_REQ_RESET_BUS:
-                hpsb_reset_bus(fi->host, LONG_RESET);
+                if (req->req.misc == RAW1394_LONG_RESET) {
+                        DBGMSG("busreset called (type: LONG)");
+                        hpsb_reset_bus(fi->host, LONG_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                if (req->req.misc == RAW1394_SHORT_RESET) {
+                        DBGMSG("busreset called (type: SHORT)");
+                        hpsb_reset_bus(fi->host, SHORT_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                /* error EINVAL (22) invalid argument */
+                return (-EINVAL);
+        case RAW1394_REQ_GET_ROM:
+                return get_config_rom(fi, req);
+
+        case RAW1394_REQ_UPDATE_ROM:
+                return update_config_rom(fi, req);
+        }
+
+        if (req->req.generation != get_hpsb_generation(fi->host)) {
+                req->req.error = RAW1394_ERROR_GENERATION;
+                req->req.generation = get_hpsb_generation(fi->host);
+                req->req.length = 0;
+                queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        switch (req->req.type) {
+        case RAW1394_REQ_PHYPACKET:
+                return write_phypacket(fi, req);
+        case RAW1394_REQ_ASYNC_SEND:
+                return handle_async_send(fi, req);
+        }
+
         if (req->req.length == 0) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
-        if (fi->host->node_id == node) {
-                return handle_local_request(fi, req, node);
-        }
-
-        return handle_remote_request(fi, req, node);
+        return handle_async_request(fi, req, node);
 }
 
 
@@ -921,6 +2029,7 @@
                 return -ENOMEM;
         
         memset(fi, 0, sizeof(struct file_info));
+        fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
 
         INIT_LIST_HEAD(&fi->list);
         fi->state = opened;
@@ -929,6 +2038,7 @@
         sema_init(&fi->complete_sem, 0);
         spin_lock_init(&fi->reqlists_lock);
         init_waitqueue_head(&fi->poll_wait_complete);
+        INIT_LIST_HEAD(&fi->addr_list);
 
         file->private_data = fi;
 
@@ -940,7 +2050,15 @@
         struct file_info *fi = file->private_data;
         struct list_head *lh;
         struct pending_request *req;
-        int done = 0, i;
+        int done = 0, i, fail = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
 
         for (i = 0; i < 64; i++) {
                 if (fi->listen_channels & (1ULL << i)) {
@@ -948,9 +2066,63 @@
                 }
         }
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         fi->listen_channels = 0;
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
+
+        fail = 0;
+        /* set address-entries invalid */
+        spin_lock_irq(&host_info_lock);
+
+        while (!list_empty(&fi->addr_list)) {
+                another_host = 0;
+                lh = fi->addr_list.next;
+                addr = list_entry(lh, struct arm_addr, addr_list);
+                /* another host with valid address-entry containing 
+                   same addressrange? */
+                list_for_each(lh_1, &host_info_list) {
+                        hi = list_entry(lh_1, struct host_info, list);
+                        if (hi->host != fi->host) {
+                                list_for_each(lh_2, &hi->file_info_list) {
+                                        fi_hlp = list_entry(lh_2, struct file_info, list);
+                                        entry = fi_hlp->addr_list.next;
+                                        while (entry != &(fi_hlp->addr_list)) {
+                                                arm_addr = list_entry(entry, 
+                                                        struct arm_addr, addr_list);
+                                                if (arm_addr->start == 
+                                                        addr->start) {
+                                                        DBGMSG("raw1394_release: "
+                                                        "another host ownes "
+                                                        "same addressrange");
+                                                        another_host = 1;
+                                                        break;
+                                                }
+                                                entry = entry->next;
+                                        }
+                                        if (another_host) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+                if (!another_host) {
+                        DBGMSG("raw1394_release: call hpsb_arm_unregister");
+                        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+                        if (!retval) {
+                                ++fail;
+                                printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
+                        }
+                }
+                DBGMSG("raw1394_release: delete addr_entry from list");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+        } /* while */
+        spin_unlock_irq(&host_info_lock);
+        if (fail > 0) {
+                printk(KERN_ERR "raw1394: during addr_list-release "
+                        "error(s) occured \n");
+        }
 
         while (!done) {
                 spin_lock_irq(&fi->reqlists_lock);
@@ -1009,28 +2181,28 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL,
-				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+        devfs_handle = devfs_register(NULL,
+                                      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
                                       IEEE1394_MAJOR,
-				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
+                                      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
         if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
-				      THIS_MODULE, &file_ops)) {
+                                      THIS_MODULE, &file_ops)) {
                 HPSB_ERR("raw1394 failed to register minor device block");
-		devfs_unregister(devfs_handle);
-		hpsb_unregister_highlevel(hl_handle);
+                devfs_unregister(devfs_handle);
+                hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
-	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
+        printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
         return 0;
 }
 
 static void __exit cleanup_raw1394(void)
 {
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
-	devfs_unregister(devfs_handle);
+        devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
 
diff -urN linux-2.4.21-pre1/drivers/ieee1394/raw1394.h linux-2.4.21-pre2/drivers/ieee1394/raw1394.h
--- linux-2.4.21-pre1/drivers/ieee1394/raw1394.h	Sun Oct  1 19:53:07 2000
+++ linux-2.4.21-pre2/drivers/ieee1394/raw1394.h	Wed Dec 18 14:16:27 2002
@@ -14,20 +14,32 @@
 #define RAW1394_REQ_SET_CARD      3
 
 /* state: connected */
-#define RAW1394_REQ_ASYNC_READ    100
-#define RAW1394_REQ_ASYNC_WRITE   101
-#define RAW1394_REQ_LOCK          102
-#define RAW1394_REQ_LOCK64        103
-#define RAW1394_REQ_ISO_SEND      104
-
-#define RAW1394_REQ_ISO_LISTEN    200
-#define RAW1394_REQ_FCP_LISTEN    201
-#define RAW1394_REQ_RESET_BUS     202
+#define RAW1394_REQ_ASYNC_READ      100
+#define RAW1394_REQ_ASYNC_WRITE     101
+#define RAW1394_REQ_LOCK            102
+#define RAW1394_REQ_LOCK64          103
+#define RAW1394_REQ_ISO_SEND        104
+#define RAW1394_REQ_ASYNC_SEND      105
+
+#define RAW1394_REQ_ISO_LISTEN      200
+#define RAW1394_REQ_FCP_LISTEN      201
+#define RAW1394_REQ_RESET_BUS       202
+#define RAW1394_REQ_GET_ROM         203
+#define RAW1394_REQ_UPDATE_ROM      204
+#define RAW1394_REQ_ECHO            205
+
+#define RAW1394_REQ_ARM_REGISTER    300
+#define RAW1394_REQ_ARM_UNREGISTER  301
+
+#define RAW1394_REQ_RESET_NOTIFY    400
+
+#define RAW1394_REQ_PHYPACKET       500
 
 /* kernel to user */
 #define RAW1394_REQ_BUS_RESET     10000
 #define RAW1394_REQ_ISO_RECEIVE   10001
 #define RAW1394_REQ_FCP_REQUEST   10002
+#define RAW1394_REQ_ARM           10003
 
 /* error codes */
 #define RAW1394_ERROR_NONE        0
@@ -45,6 +57,17 @@
 #define RAW1394_ERROR_ABORTED     (-1101)
 #define RAW1394_ERROR_TIMEOUT     (-1102)
 
+/* arm_codes */
+#define ARM_READ   1
+#define ARM_WRITE  2
+#define ARM_LOCK   4
+
+#define RAW1394_LONG_RESET  0
+#define RAW1394_SHORT_RESET 1
+
+/* busresetnotify ... */
+#define RAW1394_NOTIFY_OFF 0
+#define RAW1394_NOTIFY_ON  1
 
 #include <asm/types.h>
 
@@ -69,6 +92,29 @@
         __u8 name[32];
 };
 
+typedef struct arm_request {
+        nodeid_t        destination_nodeid;
+        nodeid_t        source_nodeid;
+        nodeaddr_t      destination_offset;
+        u8              tlabel;
+        u8              tcode;
+        u_int8_t        extended_transaction_code;
+        u_int32_t       generation;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_request_t;
+
+typedef struct arm_response {
+        int             response_code;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_response_t;
+
+typedef struct arm_request_response {
+        struct arm_request  *request;
+        struct arm_response *response;
+} *arm_request_response_t;
+
 #ifdef __KERNEL__
 
 struct iso_block_store {
@@ -91,18 +137,34 @@
         spinlock_t reqlists_lock;
         wait_queue_head_t poll_wait_complete;
 
+        struct list_head addr_list;           
+
         u8 *fcp_buffer;
 
         u64 listen_channels;
         quadlet_t *iso_buffer;
         size_t iso_buffer_length;
+
+        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
+};
+
+struct arm_addr {
+        struct list_head addr_list; /* file_info list */
+        u64    start, end;
+        u64    arm_tag;
+        u8     access_rights;
+        u8     notification_options;
+        u8     client_transactions;
+        u64    recvb;
+        u16    rec_length;
+        u8     *addr_space_buffer; /* accessed by read/write/lock */
 };
 
 struct pending_request {
         struct list_head list;
         struct file_info *file_info;
         struct hpsb_packet *packet;
-        struct tq_struct tq;
+        struct hpsb_queue_struct tq;
         struct iso_block_store *ibs;
         quadlet_t *data;
         int free_data;
diff -urN linux-2.4.21-pre1/drivers/ieee1394/sbp2.c linux-2.4.21-pre2/drivers/ieee1394/sbp2.c
--- linux-2.4.21-pre1/drivers/ieee1394/sbp2.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/sbp2.c	Wed Dec 18 14:16:27 2002
@@ -320,7 +320,6 @@
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
-#include <linux/blk.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -351,7 +350,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 707 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
@@ -421,8 +420,9 @@
  * talking to a single sbp2 device at the same time (filesystem coherency,
  * etc.). If you're running an sbp2 device that supports multiple logins,
  * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, then set sbp2_exclusive_login to
- * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
+ * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
 MODULE_PARM(sbp2_exclusive_login,"i");
@@ -800,8 +800,9 @@
 		 * Set up a task queue completion routine, which returns
 		 * the packet to the free list and releases the tlabel.
 		 */
-		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
-		request_packet->tq.data = request_packet;
+		HPSB_PREPARE_WORK(&request_packet->tq,
+				  (void (*)(void*))sbp2util_free_request_packet,
+				  request_packet);
 		request_packet->hi_context = hi;
 		hpsb_add_packet_complete_task(packet, &request_packet->tq);
 
@@ -1007,13 +1008,8 @@
 					 command->dma_size, command->dma_dir);
 			SBP2_DMA_FREE("single bulk");
 		} else if (command->dma_type == CMD_DMA_PAGE) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			pci_unmap_single(hi->host->pdev, command->cmd_dma,
-					 command->dma_size, command->dma_dir);
-#else
 			pci_unmap_page(hi->host->pdev, command->cmd_dma,
 				       command->dma_size, command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_FREE("single page");
 		} /* XXX: Check for CMD_DMA_NONE bug */
 		command->dma_type = CMD_DMA_NONE;
@@ -2146,17 +2142,11 @@
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
 			command->dma_type = CMD_DMA_PAGE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
-							   command->dma_size,
-							   command->dma_dir);
-#else
 			command->cmd_dma = pci_map_page(hi->host->pdev,
 							sgpnt[0].page,
 							sgpnt[0].offset,
 							command->dma_size,
 							command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
@@ -2702,7 +2692,7 @@
  * This function deals with status writes from the SBP-2 device
  */
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length)
+				    quadlet_t *data, u64 addr, unsigned int length, u16 fl)
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
@@ -3063,15 +3053,9 @@
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_lock_irq(&io_request_lock);
 	done (SCpnt);
 	spin_unlock_irq(&io_request_lock);
-#else
-	spin_lock_irq(hi->scsi_host->host_lock);
-	done (SCpnt);
-	spin_unlock_irq(hi->scsi_host->host_lock);
-#endif
 
 	return;
 }
@@ -3148,11 +3132,7 @@
 /*
  * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) 
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]) 
-#endif
 {
 	int heads, sectors, cylinders;
 
@@ -3160,12 +3140,12 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (int)disk->capacity / (heads * sectors);
 
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (int)disk->capacity / (heads * sectors);
 	}
 
 	geom[0] = heads;
@@ -3189,13 +3169,9 @@
 	 * we register a scsi host with the scsi stack.
 	 */
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_unlock_irq(&io_request_lock);
 	sbp2_init();
 	spin_lock_irq(&io_request_lock);
-#else
-	sbp2_init();
-#endif
 
 	/* We return the number of hosts registered. */
 	return scsi_driver_template.present;
@@ -3253,9 +3229,7 @@
 	.this_id =		-1,
 	.sg_tablesize =		SBP2_MAX_SG_ELEMENTS,
 	.use_clustering =	SBP2_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	.use_new_eh_code =	TRUE,
-#endif
 	.emulated =		1,
 	.proc_name =	SBP2_DEVICE_NAME,
 };
diff -urN linux-2.4.21-pre1/drivers/ieee1394/sbp2.h linux-2.4.21-pre2/drivers/ieee1394/sbp2.h
--- linux-2.4.21-pre1/drivers/ieee1394/sbp2.h	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/sbp2.h	Wed Dec 18 14:16:27 2002
@@ -23,13 +23,8 @@
 #define SBP2_H
 
 /* Some compatibility code */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #define SCSI_REGISTER_HOST(tmpl)	scsi_register_module(MODULE_SCSI_HA, tmpl)
 #define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_module(MODULE_SCSI_HA, tmpl)
-#else
-#define SCSI_REGISTER_HOST(tmpl)	scsi_register_host(tmpl)
-#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_host(tmpl)
-#endif
 
 #define SBP2_DEVICE_NAME		"sbp2"
 #define SBP2_DEVICE_NAME_SIZE		4
@@ -324,7 +319,7 @@
 
 	struct list_head list;
 	struct hpsb_packet *packet;
-	struct tq_struct tq;
+	struct hpsb_queue_struct tq;
 	void *hi_context;
 
 };
@@ -510,9 +505,9 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
-                                     u64 addr, unsigned int length);
+                                     u64 addr, unsigned int length, u16 flags);
 static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-                                    u64 addr, unsigned int length);
+                                    u64 addr, unsigned int length, u16 flags);
 #endif
 
 /*
@@ -522,7 +517,7 @@
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length);
+				    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags);
 static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
 				   struct scsi_id_instance_data *scsi_id,
@@ -549,11 +544,7 @@
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
-#endif
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
diff -urN linux-2.4.21-pre1/drivers/ieee1394/video1394.c linux-2.4.21-pre2/drivers/ieee1394/video1394.c
--- linux-2.4.21-pre1/drivers/ieee1394/video1394.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/ieee1394/video1394.c	Wed Dec 18 14:16:27 2002
@@ -35,7 +35,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -65,13 +64,8 @@
 #define vmalloc_32(x) vmalloc(x)
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3))
 #define remap_page_range_1394(vma, start, addr, size, prot) \
 	remap_page_range(start, addr, size, prot)
-#else
-#define remap_page_range_1394(vma, start, addr, size, prot) \
-	remap_page_range(vma, start, addr, size, prot)
-#endif
 
 struct it_dma_prg {
 	struct dma_cmd begin;
@@ -559,11 +553,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
-			get_fast_time(&d->buffer_time[i]);
-#else
 			do_gettimeofday(&d->buffer_time[i]);
-#endif
 		}
 	}
 
@@ -1455,12 +1445,7 @@
  		return -EIO;
  	}
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
-			strlen(VIDEO1394_DRIVER_NAME), NULL);
-#else
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
-#endif
 
 	hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
 	if (hl_handle == NULL) {
diff -urN linux-2.4.21-pre1/drivers/input/joydev.c linux-2.4.21-pre2/drivers/input/joydev.c
--- linux-2.4.21-pre1/drivers/input/joydev.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/input/joydev.c	Wed Dec 18 14:16:27 2002
@@ -50,6 +50,8 @@
 #define JOYDEV_MINORS		32
 #define JOYDEV_BUFFER_SIZE	64
 
+#define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
+
 struct joydev {
 	int exist;
 	int open;
@@ -134,7 +136,7 @@
 			return;
 	}  
 
-	event.time = jiffies * (1000 / HZ);
+	event.time = MSECS(jiffies);
 
 	while (list) {
 
@@ -279,7 +281,7 @@
 
 		struct js_event event;
 
-		event.time = jiffies * (1000/HZ);
+		event.time = MSECS(jiffies);
 
 		if (list->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
diff -urN linux-2.4.21-pre1/drivers/isdn/isdn_ppp.c linux-2.4.21-pre2/drivers/isdn/isdn_ppp.c
--- linux-2.4.21-pre1/drivers/isdn/isdn_ppp.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/isdn/isdn_ppp.c	Wed Dec 18 14:16:27 2002
@@ -380,7 +380,7 @@
 	is->slcomp = NULL;
 #endif
 
-/* TODO: if this was the previous master: link the the stuff to the new master */
+/* TODO: if this was the previous master: link the stuff to the new master */
 	if(is->comp_stat)
 		is->compressor->free(is->comp_stat);
 	if(is->link_comp_stat)
diff -urN linux-2.4.21-pre1/drivers/macintosh/nvram.c linux-2.4.21-pre2/drivers/macintosh/nvram.c
--- linux-2.4.21-pre1/drivers/macintosh/nvram.c	Mon Oct 15 13:43:24 2001
+++ linux-2.4.21-pre2/drivers/macintosh/nvram.c	Wed Dec 18 14:16:27 2002
@@ -113,8 +113,7 @@
 {
 	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
 		NVRAM_VERSION);
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -urN linux-2.4.21-pre1/drivers/md/lvm.c linux-2.4.21-pre2/drivers/md/lvm.c
--- linux-2.4.21-pre1/drivers/md/lvm.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/md/lvm.c	Wed Dec 18 14:16:27 2002
@@ -2253,7 +2253,7 @@
 
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		/*
-		 * Atomically make the the snapshot invisible
+		 * Atomically make the snapshot invisible
 		 * to the original lv before playing with it.
 		 */
 		lv_t * org = lv_ptr->lv_snapshot_org;
diff -urN linux-2.4.21-pre1/drivers/md/md.c linux-2.4.21-pre2/drivers/md/md.c
--- linux-2.4.21-pre1/drivers/md/md.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/md/md.c	Wed Dec 18 14:16:27 2002
@@ -445,21 +445,22 @@
 	if (rdev->sb)
 		MD_BUG();
 
-	rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL);
-	if (!rdev->sb) {
+	rdev->sb_page = alloc_page(GFP_KERNEL);
+	if (!rdev->sb_page) {
 		printk(OUT_OF_MEM);
 		return -EINVAL;
 	}
-	md_clear_page(rdev->sb);
+	rdev->sb = (mdp_super_t *) page_address(rdev->sb_page);
 
 	return 0;
 }
 
 static void free_disk_sb(mdk_rdev_t * rdev)
 {
-	if (rdev->sb) {
-		free_page((unsigned long) rdev->sb);
+	if (rdev->sb_page) {
+		page_cache_release(rdev->sb_page);
 		rdev->sb = NULL;
+		rdev->sb_page = NULL;
 		rdev->sb_offset = 0;
 		rdev->size = 0;
 	} else {
@@ -468,12 +469,43 @@
 	}
 }
 
+
+static void bh_complete(struct buffer_head *bh, int uptodate)
+{
+
+	if (uptodate)
+		set_bit(BH_Uptodate, &bh->b_state);
+
+	complete((struct completion*)bh->b_private);
+}
+
+static int sync_page_io(kdev_t dev, unsigned long sector, int size,
+			struct page *page, int rw)
+{
+	struct buffer_head bh;
+	struct completion event;
+
+	init_completion(&event);
+	init_buffer(&bh, bh_complete, &event);
+	bh.b_rdev = dev;
+	bh.b_rsector = sector;
+	bh.b_state	= (1 << BH_Req) | (1 << BH_Mapped);
+	bh.b_size = size;
+	bh.b_page = page;
+	bh.b_reqnext = NULL;
+	bh.b_data = page_address(page);
+	generic_make_request(rw, &bh);
+
+	run_task_queue(&tq_disk);
+	wait_for_completion(&event);
+
+	return test_bit(BH_Uptodate, &bh.b_state);
+}
+
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
 	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
 	kdev_t dev = rdev->dev;
-	mdp_super_t *sb;
 	unsigned long sb_offset;
 
 	if (!rdev->sb) {
@@ -487,22 +519,14 @@
 	 */
 	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
-	fsync_dev(dev);
-	set_blocksize (dev, MD_SB_BYTES);
-	bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-
-	if (bh) {
-		sb = (mdp_super_t *) bh->b_data;
-		memcpy (rdev->sb, sb, MD_SB_BYTES);
-	} else {
-		printk(NO_SB,partition_name(rdev->dev));
-		goto abort;
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) {
+		printk(NO_SB,partition_name(dev));
+		return -EINVAL;
 	}
 	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
 	ret = 0;
 abort:
-	if (bh)
-		brelse (bh);
 	return ret;
 }
 
@@ -890,10 +914,8 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	struct buffer_head *bh;
 	kdev_t dev;
 	unsigned long sb_offset, size;
-	mdp_super_t *sb;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -928,23 +950,11 @@
 	}
 
 	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
-	fsync_dev(dev);
-	set_blocksize(dev, MD_SB_BYTES);
-	bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-	if (!bh) {
-		printk(GETBLK_FAILED, partition_name(dev));
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) {
+		printk("md: write_disk_sb failed for device %s\n", partition_name(dev));
 		return 1;
 	}
-	memset(bh->b_data,0,bh->b_size);
-	sb = (mdp_super_t *) bh->b_data;
-	memcpy(sb, rdev->sb, MD_SB_BYTES);
-
-	mark_buffer_uptodate(bh, 1);
-	mark_buffer_dirty(bh);
-	ll_rw_block(WRITE, 1, &bh);
-	wait_on_buffer(bh);
-	brelse(bh);
-	fsync_dev(dev);
 skip:
 	return 0;
 }
@@ -1038,7 +1048,11 @@
 			printk("(skipping faulty ");
 		if (rdev->alias_device)
 			printk("(skipping alias ");
-
+		if (disk_faulty(&rdev->sb->this_disk)) {
+			printk("(skipping new-faulty %s )\n",
+			       partition_name(rdev->dev));
+			continue;
+		}
 		printk("%s ", partition_name(rdev->dev));
 		if (!rdev->faulty && !rdev->alias_device) {
 			printk("[events: %08lx]",
@@ -1065,7 +1079,6 @@
  *   - the device is nonexistent (zero size)
  *   - the device has no valid superblock
  *
- * a faulty rdev _never_ has rdev->sb set.
  */
 static int md_import_device(kdev_t newdev, int on_disk)
 {
@@ -1137,8 +1150,6 @@
 	md_list_add(&rdev->all, &all_raid_disks);
 	MD_INIT_LIST_HEAD(&rdev->pending);
 
-	if (rdev->faulty && rdev->sb)
-		free_disk_sb(rdev);
 	return 0;
 
 abort_free:
@@ -2337,20 +2348,16 @@
 		return -EINVAL;
 	}
 	disk = &mddev->sb->disks[rdev->desc_nr];
-	if (disk_active(disk)) {
-		MD_BUG();
+	if (disk_active(disk))
 		goto busy;
-	}
-	if (disk_removed(disk)) {
-		MD_BUG();
+
+	if (disk_removed(disk))
 		return -EINVAL;
-	}
 
 	err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
-	if (err == -EBUSY) {
-		MD_BUG();
+	if (err == -EBUSY)
 		goto busy;
-	}
+
 	if (err) {
 		MD_BUG();
 		return -EINVAL;
@@ -3056,7 +3063,6 @@
 		return 0;
 	if (!mddev->pers->error_handler
 			|| mddev->pers->error_handler(mddev,rdev) <= 0) {
-		free_disk_sb(rrdev);
 		rrdev->faulty = 1;
 	} else
 		return 1;
diff -urN linux-2.4.21-pre1/drivers/media/radio/Config.in linux-2.4.21-pre2/drivers/media/radio/Config.in
--- linux-2.4.21-pre1/drivers/media/radio/Config.in	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/media/radio/Config.in	Wed Dec 18 14:16:27 2002
@@ -30,6 +30,7 @@
 if [ "$CONFIG_ISA" = "y" ]; then
    dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
    dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+   dep_tristate '  SF16FMR2 Radio' CONFIG_RADIO_SF16FMR2 $CONFIG_VIDEO_DEV
    dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
       hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
diff -urN linux-2.4.21-pre1/drivers/media/radio/Makefile linux-2.4.21-pre2/drivers/media/radio/Makefile
--- linux-2.4.21-pre1/drivers/media/radio/Makefile	Sun Aug  5 13:15:05 2001
+++ linux-2.4.21-pre2/drivers/media/radio/Makefile	Wed Dec 18 14:16:27 2002
@@ -30,6 +30,7 @@
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
+obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
diff -urN linux-2.4.21-pre1/drivers/media/radio/radio-sf16fmr2.c linux-2.4.21-pre2/drivers/media/radio/radio-sf16fmr2.c
--- linux-2.4.21-pre1/drivers/media/radio/radio-sf16fmr2.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/media/radio/radio-sf16fmr2.c	Wed Dec 18 14:16:27 2002
@@ -0,0 +1,473 @@
+/* SF16FMR2 radio driver for Linux radio support
+ * heavily based on fmi driver...
+ * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ *
+ * Notes on the hardware
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  No volume control - only mute/unmute - you have to use line volume
+ *  
+ *  For read stereo/mono you must wait 0.1 sec after set frequency and 
+ *  card unmuted so I set frequency on unmute
+ *  Signal handling seem to work only on autoscanning (not implemented)
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <asm/semaphore.h>
+
+static struct semaphore lock;
+
+#undef DEBUG
+//#define DEBUG 1
+
+#ifdef DEBUG
+# define  debug_print(s) printk s
+#else
+# define  debug_print(s)
+#endif
+
+/* this should be static vars for module size */
+struct fmr2_device
+{
+	int port;
+	int curvol; /* 0-65535, if not volume 0 or 65535 */
+	int mute;
+	int stereo; /* card is producing stereo audio */
+	unsigned long curfreq; /* freq in kHz */
+	int card_type; 
+	__u32 flags;
+};
+
+static int io = 0x384; 
+static int radio_nr = -1;
+static int users = 0;
+
+/* hw precision is 12.5 kHz 
+ * It is only usefull to give freq in intervall of 200 (=0.0125Mhz),
+ * other bits will be truncated
+ */
+#define RSF16_ENCODE(x)	((x)/200+856)
+#define RSF16_MINFREQ 87*16000
+#define RSF16_MAXFREQ 108*16000
+
+/* from radio-aimslab */
+static void sleep_delay(unsigned long n)
+{
+	unsigned d=n/(1000000U/HZ);
+	if (!d)
+		udelay(n);
+	else
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(d);
+	}
+}
+
+static inline void wait(int n,int port)
+{
+	for (;n;--n) inb(port);
+}
+
+static void outbits(int bits, unsigned int data, int nWait, int port)
+{
+	int bit;
+	for(;--bits>=0;) {
+		bit = (data>>bits) & 1;
+		outb(bit,port);
+		wait(nWait,port);
+		outb(bit|2,port);
+		wait(nWait,port);
+		outb(bit,port);
+		wait(nWait,port);
+	}
+}
+
+static inline void fmr2_mute(int port)
+{
+	outb(0x00, port);
+	wait(4,port);
+}
+
+static inline void fmr2_unmute(int port)
+{
+	outb(0x04, port);
+	wait(4,port);
+}
+
+static inline int fmr2_stereo_mode(int port)
+{
+	int n = inb(port);
+	outb(6,port);
+	inb(port);
+	n = ((n>>3)&1)^1;
+	debug_print((KERN_DEBUG "stereo: %d\n", n));
+	return n;
+}
+
+static int fmr2_product_info(struct fmr2_device *dev)
+{
+	int n = inb(dev->port);
+	n &= 0xC1;
+	if (n == 0)
+	{
+		/* this should support volume set */
+		dev->card_type = 12;
+		return 0;
+	}
+	/* not volume (mine is 11) */
+	dev->card_type = (n==128)?11:0;
+	return n;
+}
+
+static inline int fmr2_getsigstr(struct fmr2_device *dev)
+{
+	/* !!! work only if scanning freq */
+	int port = dev->port, res = 0xffff;
+	outb(5,port);
+	wait(4,port);
+	if (!(inb(port)&1)) res = 0;
+	debug_print((KERN_DEBUG "signal: %d\n", res));
+	return res;
+}
+
+/* set frequency and unmute card */
+static int fmr2_setfreq(struct fmr2_device *dev)
+{
+	int port = dev->port;
+	unsigned long freq = dev->curfreq;
+
+	fmr2_mute(port);
+
+	/* 0x42 for mono output
+	 * 0x102 forward scanning
+	 * 0x182 scansione avanti 
+	 */
+	outbits(9,0x2,3,port);
+	outbits(16,RSF16_ENCODE(freq),2,port);
+
+	fmr2_unmute(port);
+
+	/* wait 0.11 sec */
+	sleep_delay(110000LU);
+
+	/* NOTE if mute this stop radio
+	   you must set freq on unmute */
+	dev->stereo = fmr2_stereo_mode(port);
+	return 0;
+}
+
+/* !!! not tested, in my card this does't work !!! */
+static int fmr2_setvolume(struct fmr2_device *dev)
+{
+	int i,a,n, port = dev->port;
+
+	if (dev->card_type != 11) return 1;
+
+	switch( (dev->curvol+(1<<11)) >> 12 )
+	{
+	case 0: case 1: n = 0x21; break;
+	case 2: n = 0x84; break;
+	case 3: n = 0x90; break;
+	case 4: n = 0x104; break;
+	case 5: n = 0x110; break;
+	case 6: n = 0x204; break;
+	case 7: n = 0x210; break;
+	case 8: n = 0x402; break;
+	case 9: n = 0x404; break;
+	default:
+	case 10: n = 0x408; break;
+	case 11: n = 0x410; break;
+	case 12: n = 0x801; break;
+	case 13: n = 0x802; break;
+	case 14: n = 0x804; break;
+	case 15: n = 0x808; break;
+	case 16: n = 0x810; break;
+	}
+	for(i=12;--i>=0;)
+	{
+		a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	for(i=6;--i>=0;)
+	{
+		a = ((0x18 >> i) & 1) << 6;
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	wait(4,port);
+	outb(0x14, port);
+
+	return 0;
+}
+
+static int fmr2_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct fmr2_device *fmr2=dev->priv;
+	debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
+		"stereo %d type %d\n",
+		fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, 
+		fmr2->stereo, fmr2->card_type));
+	
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			strcpy(v.name, "SF16-FMR2 radio");
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			int mult;
+
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */
+				return -EINVAL;
+			strcpy(v.name, "FM");
+			mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v.rangelow = RSF16_MINFREQ/mult;
+			v.rangehigh = RSF16_MAXFREQ/mult;
+			v.flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
+			if (fmr2->mute)
+				v.flags |= VIDEO_AUDIO_MUTE;
+			v.mode=VIDEO_MODE_AUTO;
+			down(&lock);
+			v.signal = fmr2_getsigstr(fmr2);
+			up(&lock);
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			fmr2->flags = v.flags & VIDEO_TUNER_LOW;
+			return 0;
+		}
+		case VIDIOCGFREQ:
+		{
+			unsigned long tmp = fmr2->curfreq;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp /= 1000;
+			if(copy_to_user(arg, &tmp, sizeof(tmp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFREQ:
+		{
+			unsigned long tmp;
+			if(copy_from_user(&tmp, arg, sizeof(tmp)))
+				return -EFAULT;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp *= 1000;
+			if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
+				return -EINVAL;
+			/* rounding in steps of 200 to match th freq
+			 * that will be used 
+			 */
+			fmr2->curfreq = (tmp/200)*200; 
+
+			/* set card freq (if not muted) */
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				down(&lock);
+				fmr2_setfreq(fmr2);
+				up(&lock);
+			}
+			return 0;
+		}
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio v;
+			v.audio=0;
+			v.volume=0;
+			v.bass=0;
+			v.treble=0;
+			/* !!! do not return VIDEO_AUDIO_MUTE */
+			v.flags = VIDEO_AUDIO_MUTABLE;
+			strcpy(v.name, "Radio");
+			/* get current stereo mode */
+			v.mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
+			v.balance = 0;
+			v.step=0; /* No volume, just (un)mute */
+			/* volume supported ? */
+			if (fmr2->card_type == 11)
+			{
+				v.flags |= VIDEO_AUDIO_VOLUME;
+				v.step = 1 << 12;
+				v.volume = fmr2->curvol;
+			}
+			debug_print((KERN_DEBUG "Get flags %d vol %d\n", v.flags, v.volume));
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.audio)
+				return -EINVAL;
+			debug_print((KERN_DEBUG "Set flags %d vol %d\n", v.flags, v.volume));
+			/* set volume */
+			if (v.flags & VIDEO_AUDIO_VOLUME)
+				fmr2->curvol = v.volume; /* !!! set with precision */
+			if (fmr2->card_type != 11) fmr2->curvol = 65535;
+			fmr2->mute = 0;
+			if (v.flags&VIDEO_AUDIO_MUTE)
+				fmr2->mute = 1;
+#ifdef DEBUG
+			if (fmr2->curvol && !fmr2->mute)
+				printk(KERN_DEBUG "unmute\n");
+			else
+				printk(KERN_DEBUG "mute\n");
+#endif
+			down(&lock);
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				fmr2_setvolume(fmr2);
+				fmr2_setfreq(fmr2);
+			}
+			else fmr2_mute(fmr2->port);
+			up(&lock);
+			return 0;
+		}
+		case VIDIOCGUNIT:
+		{
+			struct video_unit v;
+			v.video=VIDEO_NO_UNIT;
+			v.vbi=VIDEO_NO_UNIT;
+			v.radio=dev->minor;
+			v.audio=0; /* How do we find out this??? */
+			v.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int fmr2_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	return 0;
+}
+
+static void fmr2_close(struct video_device *dev)
+{
+	users--;
+}
+
+static struct fmr2_device fmr2_unit;
+
+static struct video_device fmr2_radio=
+{
+	owner:		THIS_MODULE,
+	name:		"SF16FMR2 radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_SF16FMR2,
+	open:		fmr2_open,
+	close:		fmr2_close,
+	ioctl:		fmr2_ioctl,
+};
+
+static int __init fmr2_init(void)
+{
+	if (check_region(io, 2)) 
+	{
+		printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	fmr2_unit.port = io;
+	fmr2_unit.curvol = 0;
+	fmr2_unit.mute = 0;
+	fmr2_unit.curfreq = 0;
+	fmr2_unit.stereo = 1;
+	fmr2_unit.flags = VIDEO_TUNER_LOW;
+	fmr2_unit.card_type = 0;
+	fmr2_radio.priv = &fmr2_unit;
+
+	init_MUTEX(&lock);
+
+	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+		return -EINVAL;
+
+	request_region(io, 2, "fmr2");
+	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
+	/* mute card - prevents noisy bootups */
+	down(&lock);
+	fmr2_mute(io);
+	fmr2_product_info(&fmr2_unit);
+	up(&lock);
+	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+	return 0;
+}
+
+MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+MODULE_PARM(radio_nr, "i");
+
+EXPORT_NO_SYMBOLS;
+
+static void __exit fmr2_cleanup_module(void)
+{
+	video_unregister_device(&fmr2_radio);
+	release_region(io,2);
+}
+
+module_init(fmr2_init);
+module_exit(fmr2_cleanup_module);
+
+#ifndef MODULE
+
+static int __init fmr2_setup_io(char *str)
+{
+	get_option(&str, &io);
+	return 1;
+}
+
+__setup("sf16fmr2=", fmr2_setup_io);
+
+#endif
diff -urN linux-2.4.21-pre1/drivers/media/video/Config.in linux-2.4.21-pre2/drivers/media/video/Config.in
--- linux-2.4.21-pre1/drivers/media/video/Config.in	Fri Dec 21 09:41:54 2001
+++ linux-2.4.21-pre2/drivers/media/video/Config.in	Wed Dec 18 14:16:27 2002
@@ -49,7 +49,7 @@
 dep_tristate '  Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
 dep_tristate '  Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
+  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
 fi
 
 endmenu
diff -urN linux-2.4.21-pre1/drivers/media/video/pms.c linux-2.4.21-pre2/drivers/media/video/pms.c
--- linux-2.4.21-pre1/drivers/media/video/pms.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/media/video/pms.c	Wed Dec 18 14:16:27 2002
@@ -622,7 +622,7 @@
 }
 
 
-static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
+static int pms_capture(struct pms_device *dev, char *buf, int rgb555, unsigned long count)
 {
 	int y;
 	int dw = 2*dev->width;
diff -urN linux-2.4.21-pre1/drivers/message/i2o/i2o_config.c linux-2.4.21-pre2/drivers/message/i2o/i2o_config.c
--- linux-2.4.21-pre1/drivers/message/i2o/i2o_config.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/message/i2o/i2o_config.c	Wed Dec 18 14:16:27 2002
@@ -918,7 +918,7 @@
 		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
 		return -ENOBUFS;
 	}
-	if(misc_register(&i2o_miscdev)==-1)
+	if(misc_register(&i2o_miscdev) < 0)
 	{
 		printk(KERN_ERR "i2o_config: can't register device.\n");
 		kfree(page_buf);
diff -urN linux-2.4.21-pre1/drivers/net/at1700.c linux-2.4.21-pre2/drivers/net/at1700.c
--- linux-2.4.21-pre1/drivers/net/at1700.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/net/at1700.c	Wed Dec 18 14:16:27 2002
@@ -311,7 +311,6 @@
 		&& inb(ioaddr + SAPROM + 2) == 0x0e)
 		is_fmv18x = 1;
 	else {
-		ret = -ENODEV;
 		goto err_out;
 	}
 			
@@ -336,11 +335,10 @@
 			}
 			if (i == 8) {
 				goto err_out;
-				ret = -ENODEV;
 			}
 		} else {
 			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				return -ENODEV;
+				goto err_out;
 			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
 		}
 	}
diff -urN linux-2.4.21-pre1/drivers/net/bonding.c linux-2.4.21-pre2/drivers/net/bonding.c
--- linux-2.4.21-pre1/drivers/net/bonding.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/net/bonding.c	Wed Dec 18 14:16:28 2002
@@ -686,7 +686,7 @@
 }
 
 /*
- * This function counts the the number of attached 
+ * This function counts the number of attached 
  * slaves for use by bond_xmit_xor.
  */
 static void update_slave_cnt(bonding_t *bond)
diff -urN linux-2.4.21-pre1/drivers/net/irda/ali-ircc.c linux-2.4.21-pre2/drivers/net/irda/ali-ircc.c
--- linux-2.4.21-pre1/drivers/net/irda/ali-ircc.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/net/irda/ali-ircc.c	Wed Dec 18 14:16:28 2002
@@ -2017,22 +2017,19 @@
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();	
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__);
-		/*
-		 * This function will also be used by IrLAP to change the
-		 * speed, so we still must allow for speed change within
-		 * interrupt context.
-		 */
-		if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+		/* Root only */
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		ali_ircc_change_speed(self, irq->ifr_baudrate);		
+		restore_flags(flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__);
@@ -2042,14 +2039,17 @@
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__);
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		irq->ifr_receiving = ali_ircc_is_receiving(self);
+		restore_flags(flags);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
-	
+
 	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return ret;
diff -urN linux-2.4.21-pre1/drivers/net/irda/irtty.c linux-2.4.21-pre2/drivers/net/irda/irtty.c
--- linux-2.4.21-pre1/drivers/net/irda/irtty.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/net/irda/irtty.c	Wed Dec 18 14:16:28 2002
@@ -966,9 +966,14 @@
 
 	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	/* Locking :
+	 * irda_device_dongle_init() can't be locked.
+	 * irda_task_execute() doesn't need to be locked (but
+	 * irtty_change_speed() should protect itself).
+	 * As this driver doesn't have spinlock protection, keep
+	 * old fashion locking :-(
+	 * Jean II
+	 */
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -994,14 +999,17 @@
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		self->dongle = dongle;
-
-		/* Now initialize the dongle!  */
+		/* Now initialize the dongle!
+		 * Safe to do unlocked : self->dongle is still NULL. */ 
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
@@ -1015,21 +1023,27 @@
 	case SIOCSDTRRTS:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+			restore_flags(flags);
+		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
+			restore_flags(flags);
+		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
 	
-	restore_flags(flags);
-	
 	return ret;
 }
 
diff -urN linux-2.4.21-pre1/drivers/net/irda/smc-ircc.c linux-2.4.21-pre2/drivers/net/irda/smc-ircc.c
--- linux-2.4.21-pre1/drivers/net/irda/smc-ircc.c	Thu Nov 28 15:53:13 2002
+++ linux-2.4.21-pre2/drivers/net/irda/smc-ircc.c	Wed Dec 18 14:16:28 2002
@@ -10,6 +10,8 @@
  * Modified by:   Dag Brattli <dag@brattli.net>
  * Modified at:   Tue Jun 26 2001
  * Modified by:   Stefani Seibold <stefani@seibold.net>
+ * Modified at:   Thur Apr 18 2002
+ * Modified by:   Jeff Snyder <je4d@pobox.com>
  * 
  *     Copyright (c) 2001      Stefani Seibold
  *     Copyright (c) 1999-2001 Dag Brattli
@@ -537,7 +539,7 @@
 	if (ircc_irq < 255) {
 		if (ircc_irq!=irq)
 			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
-				driver_name, self->io->irq, ircc_irq);
+				driver_name, irq, ircc_irq);
 		self->io->irq = ircc_irq;
 	}
 	else
@@ -545,13 +547,13 @@
 	if (ircc_dma < 255) {
 		if (ircc_dma!=dma)
 			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
-				driver_name, self->io->dma, ircc_dma);
+				driver_name, dma, ircc_dma);
 		self->io->dma = ircc_dma;
 	}
 	else
 		self->io->dma = dma;
 
-	request_region(fir_base, CHIP_IO_EXTENT, driver_name);
+	request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
@@ -1187,10 +1189,9 @@
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", 
-		__FUNCTION__, self->io->fir_base);
+	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, iobase);
 
-	release_region(self->io->fir_base, self->io->fir_ext);
+	release_region(iobase, CHIP_IO_EXTENT);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
diff -urN linux-2.4.21-pre1/drivers/net/sis900.c linux-2.4.21-pre2/drivers/net/sis900.c
--- linux-2.4.21-pre1/drivers/net/sis900.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/net/sis900.c	Wed Dec 18 14:16:28 2002
@@ -532,6 +532,13 @@
 		
 		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
 			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
+			mii_phy = sis_priv->first_mii;
+			while (mii_phy) {
+				struct mii_phy *phy;
+				phy = mii_phy;
+				mii_phy = mii_phy->next;
+				kfree(phy);
+			}
 			return 0;
 		}
 		
diff -urN linux-2.4.21-pre1/drivers/net/tg3.c linux-2.4.21-pre2/drivers/net/tg3.c
--- linux-2.4.21-pre1/drivers/net/tg3.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/net/tg3.c	Wed Dec 18 14:16:28 2002
@@ -33,15 +33,6 @@
 #define PCI_DMA_BUS_IS_PHYS 1
 #endif
 
-/* Either I can't figure out how they secretly implemented it (ie. RXD flags
- * for mini ring, where it should go in NIC sram, and how many entries the NIC
- * firmware expects) or it isn't really fully implemented.  Perhaps Broadcom
- * wants people to pay for a "performance enhanced" version of their firmware +
- * binary-only driver that has the mini ring actually implemented.
- * These kids today... -DaveM
- */
-#define TG3_MINI_RING_WORKS 0
-
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define TG3_VLAN_TAG_USED 1
 #else
@@ -59,8 +50,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.2"
-#define DRV_MODULE_RELDATE	"Nov 14, 2002"
+#define DRV_MODULE_VERSION	"1.2a"
+#define DRV_MODULE_RELDATE	"Dec 9, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -90,10 +81,6 @@
  */
 #define TG3_RX_RING_SIZE		512
 #define TG3_DEF_RX_RING_PENDING		200
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_SIZE		256 /* ??? */
-#define TG3_DEF_RX_MINI_RING_PENDING	100
-#endif
 #define TG3_RX_JUMBO_RING_SIZE		256
 #define TG3_DEF_RX_JUMBO_RING_PENDING	100
 #define TG3_RX_RCB_RING_SIZE		1024
@@ -102,10 +89,6 @@
 
 #define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 				 TG3_RX_RING_SIZE)
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
-				 TG3_RX_MINI_RING_SIZE)
-#endif
 #define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 			         TG3_RX_JUMBO_RING_SIZE)
 #define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
@@ -121,9 +104,6 @@
 #define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
 #define RX_PKT_BUF_SZ		(1536 + tp->rx_offset + 64)
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_PKT_BUF_SZ	(256 + tp->rx_offset + 64)
-#endif
 #define RX_JUMBO_PKT_BUF_SZ	(9046 + tp->rx_offset + 64)
 
 /* minimum number of free TX descriptors required to wake up TX process */
@@ -1784,16 +1764,7 @@
 			src_map = &tp->rx_jumbo_buffers[src_idx];
 		skb_size = RX_JUMBO_PKT_BUF_SZ;
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		desc = &tp->rx_mini[dest_idx];
-		map = &tp->rx_mini_buffers[dest_idx];
-		if (src_idx >= 0)
-			src_map = &tp->rx_mini_buffers[src_idx];
-		skb_size = RX_MINI_PKT_BUF_SZ;
-		break;
-#endif
+
 	default:
 		return -EINVAL;
 	};
@@ -1854,15 +1825,7 @@
 		src_desc = &tp->rx_jumbo[src_idx];
 		src_map = &tp->rx_jumbo_buffers[src_idx];
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		dest_desc = &tp->rx_mini[dest_idx];
-		dest_map = &tp->rx_mini_buffers[dest_idx];
-		src_desc = &tp->rx_mini[src_idx];
-		src_map = &tp->rx_mini_buffers[src_idx];
-		break;
-#endif
+
 	default:
 		return;
 	};
@@ -1938,14 +1901,6 @@
 			skb = tp->rx_jumbo_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_jumbo_ptr;
 		}
-#if TG3_MINI_RING_WORKS
-		else if (opaque_key == RXD_OPAQUE_RING_MINI) {
-			dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
-						  mapping);
-			skb = tp->rx_mini_buffers[desc_idx].skb;
-			post_ptr = &tp->rx_mini_ptr;
-		}
-#endif
 		else {
 			goto next_pkt_nopost;
 		}
@@ -1965,7 +1920,6 @@
 
 		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
 
-		/* Kill the copy case if we ever get the mini ring working. */
 		if (len > RX_COPY_THRESHOLD) {
 			int skb_size;
 
@@ -2051,15 +2005,6 @@
 		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 			tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
-#if TG3_MINI_RING_WORKS
-	if (work_mask & RXD_OPAQUE_RING_MINI) {
-		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
-		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-			     sw_idx);
-		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-			tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-	}
-#endif
 
 	return received;
 }
@@ -2734,20 +2679,7 @@
 		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		rxp = &tp->rx_mini_buffers[i];
 
-		if (rxp->skb == NULL)
-			continue;
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(rxp, mapping),
-				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
-				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb_any(rxp->skb);
-		rxp->skb = NULL;
-	}
-#endif
 	for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 		rxp = &tp->rx_jumbo_buffers[i];
 
@@ -2812,9 +2744,6 @@
 
 	/* Zero out all descriptors. */
 	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
-#if TG3_MINI_RING_WORKS
-	memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES);
-#endif
 	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
 	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES);
 
@@ -2847,19 +2776,7 @@
 		rxd->opaque = (RXD_OPAQUE_RING_STD |
 			       (i << RXD_OPAQUE_INDEX_SHIFT));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		struct tg3_rx_buffer_desc *rxd;
 
-		rxd = &tp->rx_mini[i];
-		rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64)
-			<< RXD_LEN_SHIFT;
-		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
-			RXD_FLAG_MINI;
-		rxd->opaque = (RXD_OPAQUE_RING_MINI |
-			       (i << RXD_OPAQUE_INDEX_SHIFT));
-	}
-#endif
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 			struct tg3_rx_buffer_desc *rxd;
@@ -2881,14 +2798,6 @@
 			break;
 	}
 
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < tp->rx_mini_pending; i++) {
-		if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI,
-				     -1, i) < 0)
-			break;
-	}
-#endif
-
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < tp->rx_jumbo_pending; i++) {
 			if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
@@ -2913,13 +2822,6 @@
 				    tp->rx_std, tp->rx_std_mapping);
 		tp->rx_std = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	if (tp->rx_mini) {
-		pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-				    tp->rx_mini, tp->rx_mini_mapping);
-		tp->rx_mini = NULL;
-	}
-#endif
 	if (tp->rx_jumbo) {
 		pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 				    tp->rx_jumbo, tp->rx_jumbo_mapping);
@@ -2955,9 +2857,6 @@
 {
 	tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
 				      (TG3_RX_RING_SIZE +
-#if TG3_MINI_RING_WORKS
-				       TG3_RX_MINI_RING_SIZE +
-#endif
 				       TG3_RX_JUMBO_RING_SIZE)) +
 				     (sizeof(struct tx_ring_info) *
 				      TG3_TX_RING_SIZE),
@@ -2965,29 +2864,14 @@
 	if (!tp->rx_std_buffers)
 		return -ENOMEM;
 
-#if TG3_MINI_RING_WORKS
 	memset(tp->rx_std_buffers, 0,
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
-		 TG3_RX_MINI_RING_SIZE +
 		 TG3_RX_JUMBO_RING_SIZE)) +
 	       (sizeof(struct tx_ring_info) *
 		TG3_TX_RING_SIZE));
-#else
-	memset(tp->rx_std_buffers, 0,
-	       (sizeof(struct ring_info) *
-		(TG3_RX_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE)) +
-	       (sizeof(struct tx_ring_info) *
-		TG3_TX_RING_SIZE));
-#endif
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-	tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE];
-#else
 	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-#endif
 	tp->tx_buffers = (struct tx_ring_info *)
 		&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
 
@@ -2996,14 +2880,6 @@
 	if (!tp->rx_std)
 		goto err_out;
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-					   &tp->rx_mini_mapping);
-
-	if (!tp->rx_mini)
-		goto err_out;
-#endif
-
 	tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 					    &tp->rx_jumbo_mapping);
 
@@ -4119,8 +3995,6 @@
 	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
 	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
 	 *
-	 * ??? No space allocated for mini receive ring? :(
-	 *
 	 * The size of each ring is fixed in the firmware, but the location is
 	 * configurable.
 	 */
@@ -4133,19 +4007,8 @@
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
 	     NIC_SRAM_RX_BUFFER_DESC);
 
-#if TG3_MINI_RING_WORKS
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
-	     ((u64) tp->rx_mini_mapping >> 32));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
-	     ((u64) tp->rx_mini_mapping & 0xffffffff));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
-	     RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR,
-	     NIC_SRAM_RX_MINI_BUFFER_DESC);
-#else
 	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
 	     BDINFO_FLAGS_DISABLED);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -4163,9 +4026,6 @@
 
 	/* Setup replenish thresholds. */
 	tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
-#if TG3_MINI_RING_WORKS
-	tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8);
-#endif
 	tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
 
 	/* Clear out send RCB ring in SRAM. */
@@ -4213,13 +4073,6 @@
 		     tp->rx_std_ptr);
 	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 		tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_ptr = tp->rx_mini_pending;
-	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-		     tp->rx_mini_ptr);
-	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-		tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
 		tp->rx_jumbo_ptr = tp->rx_jumbo_pending;
@@ -4840,23 +4693,6 @@
 		       readl(rxd + 0x0), readl(rxd + 0x4),
 		       readl(rxd + 0x8), readl(rxd + 0xc));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < 6; i++) {
-		unsigned long rxd;
-
-		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC
-			+ (i * sizeof(struct tg3_rx_buffer_desc));
-		printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-		rxd += (4 * sizeof(u32));
-		printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-	}
-#endif
 
 	for (i = 0; i < 6; i++) {
 		unsigned long rxd;
@@ -5387,19 +5223,11 @@
 		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 
 		ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1;
-#else
 		ering.rx_mini_max_pending = 0;
-#endif
 		ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
 
 		ering.rx_pending = tp->rx_pending;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_pending = tp->rx_mini_pending;
-#else
 		ering.rx_mini_pending = 0;
-#endif
 		ering.rx_jumbo_pending = tp->rx_jumbo_pending;
 		ering.tx_pending = tp->tx_pending;
 
@@ -5414,9 +5242,6 @@
 			return -EFAULT;
 
 		if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
-#if TG3_MINI_RING_WORKS
-		    (ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) ||
-#endif
 		    (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
 		    (ering.tx_pending > TG3_TX_RING_SIZE - 1))
 			return -EINVAL;
@@ -5425,9 +5250,6 @@
 		spin_lock(&tp->tx_lock);
 
 		tp->rx_pending = ering.rx_pending;
-#if TG3_MINI_RING_WORKS
-		tp->rx_mini_pending = ering.rx_mini_pending;
-#endif
 		tp->rx_jumbo_pending = ering.rx_jumbo_pending;
 		tp->tx_pending = ering.tx_pending;
 
@@ -6150,6 +5972,13 @@
 	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
 
+	/* Chip-specific fixup from Broadcom driver */
+	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
+		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
+	}
+
 	/* Force the chip into D0. */
 	err = tg3_set_power_state(tp, 0);
 	if (err)
@@ -6839,9 +6668,6 @@
 	tg3_init_bufmgr_config(tp);
 
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING;
-#endif
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 	tp->tx_pending = TG3_DEF_TX_RING_PENDING;
 
diff -urN linux-2.4.21-pre1/drivers/net/tg3.h linux-2.4.21-pre2/drivers/net/tg3.h
--- linux-2.4.21-pre1/drivers/net/tg3.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/net/tg3.h	Wed Dec 18 14:16:28 2002
@@ -25,9 +25,6 @@
 
 #define RX_STD_MAX_SIZE			1536
 #define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_MAX_SIZE		256
-#endif
 
 /* First 256 bytes are a mirror of PCI config space. */
 #define TG3PCI_VENDOR			0x00000000
@@ -1301,9 +1298,7 @@
 #define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
 #define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
 
-#if TG3_MINI_RING_WORKS
 #define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
-#endif
 
 #define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
 #define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
@@ -1453,9 +1448,7 @@
 #define RXD_FLAGS_SHIFT	0
 
 #define RXD_FLAG_END			0x0004
-#if TG3_MINI_RING_WORKS
 #define RXD_FLAG_MINI			0x0800
-#endif
 #define RXD_FLAG_JUMBO			0x0020
 #define RXD_FLAG_VLAN			0x0040
 #define RXD_FLAG_ERROR			0x0400
@@ -1490,9 +1483,7 @@
 #define RXD_OPAQUE_INDEX_SHIFT		0
 #define RXD_OPAQUE_RING_STD		0x00010000
 #define RXD_OPAQUE_RING_JUMBO		0x00020000
-#if TG3_MINI_RING_WORKS
 #define RXD_OPAQUE_RING_MINI		0x00040000
-#endif
 #define RXD_OPAQUE_RING_MASK		0x00070000
 };
 
@@ -1728,6 +1719,8 @@
 };
 
 struct tg3 {
+	/* begin "general, frequently-used members" cacheline section */
+
 	/* SMP locking strategy:
 	 *
 	 * lock: Held during all operations except TX packet
@@ -1741,18 +1734,51 @@
 	 * necessary for acquisition of 'tx_lock'.
 	 */
 	spinlock_t			lock;
-	spinlock_t			tx_lock;
+	spinlock_t			indirect_lock;
 
+	unsigned long			regs;
+	struct net_device		*dev;
+	struct pci_dev			*pdev;
+
+	struct tg3_hw_status		*hw_status;
+	dma_addr_t			status_mapping;
+
+	u32				msg_enable;
+
+	/* begin "tx thread" cacheline section */
 	u32				tx_prod;
 	u32				tx_cons;
+	u32				tx_pending;
+
+	spinlock_t			tx_lock;
+
+	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
+	struct tg3_tx_buffer_desc	*tx_ring;
+	struct tx_ring_info		*tx_buffers;
+	dma_addr_t			tx_desc_mapping;
+
+	/* begin "rx thread" cacheline section */
 	u32				rx_rcb_ptr;
 	u32				rx_std_ptr;
 	u32				rx_jumbo_ptr;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_ptr;
+	u32				rx_pending;
+	u32				rx_jumbo_pending;
+#if TG3_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
 #endif
-	spinlock_t			indirect_lock;
 
+	struct tg3_rx_buffer_desc	*rx_std;
+	struct ring_info		*rx_std_buffers;
+	dma_addr_t			rx_std_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_jumbo;
+	struct ring_info		*rx_jumbo_buffers;
+	dma_addr_t			rx_jumbo_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_rcb;
+	dma_addr_t			rx_rcb_mapping;
+
+	/* begin "everything else" cacheline(s) section */
 	struct net_device_stats		net_stats;
 	struct net_device_stats		net_stats_prev;
 	unsigned long			phy_crc_errors;
@@ -1791,8 +1817,6 @@
 #define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 
-	u32				msg_enable;
-
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
 
@@ -1806,13 +1830,6 @@
 	struct tg3_link_config		link_config;
 	struct tg3_bufmgr_config	bufmgr_config;
 
-	u32				rx_pending;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_pending;
-#endif
-	u32				rx_jumbo_pending;
-	u32				tx_pending;
-
 	/* cache h/w values, often passed straight to h/w */
 	u32				rx_mode;
 	u32				tx_mode;
@@ -1865,36 +1882,6 @@
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
-	unsigned long			regs;
-	struct pci_dev			*pdev;
-	struct net_device		*dev;
-#if TG3_VLAN_TAG_USED
-	struct vlan_group		*vlgrp;
-#endif
-
-	struct tg3_rx_buffer_desc	*rx_std;
-	struct ring_info		*rx_std_buffers;
-	dma_addr_t			rx_std_mapping;
-#if TG3_MINI_RING_WORKS
-	struct tg3_rx_buffer_desc	*rx_mini;
-	struct ring_info		*rx_mini_buffers;
-	dma_addr_t			rx_mini_mapping;
-#endif
-	struct tg3_rx_buffer_desc	*rx_jumbo;
-	struct ring_info		*rx_jumbo_buffers;
-	dma_addr_t			rx_jumbo_mapping;
-
-	struct tg3_rx_buffer_desc	*rx_rcb;
-	dma_addr_t			rx_rcb_mapping;
-
-	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
-	struct tg3_tx_buffer_desc	*tx_ring;
-	struct tx_ring_info		*tx_buffers;
-	dma_addr_t			tx_desc_mapping;
-
-	struct tg3_hw_status		*hw_status;
-	dma_addr_t			status_mapping;
-
 	struct tg3_hw_stats		*hw_stats;
 	dma_addr_t			stats_mapping;
 };
diff -urN linux-2.4.21-pre1/drivers/net/tulip/interrupt.c linux-2.4.21-pre2/drivers/net/tulip/interrupt.c
--- linux-2.4.21-pre1/drivers/net/tulip/interrupt.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/net/tulip/interrupt.c	Wed Dec 18 14:16:28 2002
@@ -263,7 +263,7 @@
            This would turn on IM for devices that is not contributing
            to backlog congestion with unnecessary latency.
 
-           We monitor the the device RX-ring and have:
+           We monitor the device RX-ring and have:
 
            HW Interrupt Mitigation either ON or OFF.
 
diff -urN linux-2.4.21-pre1/drivers/pci/pci.c linux-2.4.21-pre2/drivers/pci/pci.c
--- linux-2.4.21-pre1/drivers/pci/pci.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/pci/pci.c	Wed Dec 18 14:16:28 2002
@@ -932,14 +932,13 @@
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
 	cache_size <<= 2;
 	if (cache_size != SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "
-		       "(%i bytes) by BIOS/FW, ",
+		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly (%i bytes) by BIOS/FW.\n",
 		       dev->slot_name, cache_size);
 		if (cache_size > SMP_CACHE_BYTES) {
-			printk("expecting %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s cache line size too large - expecting %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			rc = -EINVAL;
 		} else {
-			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s PCI cache line size corrected to %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
 					      SMP_CACHE_BYTES >> 2);
 		}
diff -urN linux-2.4.21-pre1/drivers/pcmcia/sa1100_generic.c linux-2.4.21-pre2/drivers/pcmcia/sa1100_generic.c
--- linux-2.4.21-pre1/drivers/pcmcia/sa1100_generic.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/pcmcia/sa1100_generic.c	Wed Dec 18 14:16:28 2002
@@ -47,7 +47,6 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
-#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
diff -urN linux-2.4.21-pre1/drivers/s390/block/dasd.c linux-2.4.21-pre2/drivers/s390/block/dasd.c
--- linux-2.4.21-pre1/drivers/s390/block/dasd.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/s390/block/dasd.c	Wed Dec 18 14:16:28 2002
@@ -1315,9 +1315,9 @@
 /*
  * DASD_TERM_IO
  *
- * attempts to terminate the the current IO and set it to failed if termination
+ * Attempts to terminate the current IO and set it to failed if termination
  * was successful.
- * returns an appropriate return code
+ * Returns an appropriate return code.
  */
 int
 dasd_term_IO (ccw_req_t * cqr)
diff -urN linux-2.4.21-pre1/drivers/s390/block/dasd_3990_erp.c linux-2.4.21-pre2/drivers/s390/block/dasd_3990_erp.c
--- linux-2.4.21-pre1/drivers/s390/block/dasd_3990_erp.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.21-pre2/drivers/s390/block/dasd_3990_erp.c	Wed Dec 18 14:16:28 2002
@@ -2712,10 +2712,10 @@
  * DASD_3990_ERP_ERROR_MATCH
  *
  * DESCRIPTION
- *   check if the the device status of the given cqr is the same.
+ *   Check if the device status of the given cqr is the same.
  *   This means that the failed CCW and the relevant sense data
  *   must match.
- *   I don't distinguish between 24 and 32 byte sense becaus in case of
+ *   I don't distinguish between 24 and 32 byte sense because in case of
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
diff -urN linux-2.4.21-pre1/drivers/s390/s390io.c linux-2.4.21-pre2/drivers/s390/s390io.c
--- linux-2.4.21-pre1/drivers/s390/s390io.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/s390/s390io.c	Wed Dec 18 14:16:28 2002
@@ -8607,7 +8607,7 @@
 cio_ignore_proc_write (struct file *file, const char *user_buf,
 		       size_t user_len, loff_t * offset)
 {
-	char *buffer
+	char *buffer;
 	
 	if(user_len > 65536)
 		user_len = 65536;
diff -urN linux-2.4.21-pre1/drivers/scsi/Config.in linux-2.4.21-pre2/drivers/scsi/Config.in
--- linux-2.4.21-pre1/drivers/scsi/Config.in	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/scsi/Config.in	Wed Dec 18 14:16:28 2002
@@ -204,6 +204,7 @@
 if [ "$CONFIG_X86" = "y" ]; then
    dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 fi
+dep_tristate 'Workbit NinjaSCSI-32Bi/UDE support' CONFIG_SCSI_NSP32 $CONFIG_SCSI
 #
 # Note - this is a very special 'host' adapter that simulates the presence of some disks.
 # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
diff -urN linux-2.4.21-pre1/drivers/scsi/Makefile linux-2.4.21-pre2/drivers/scsi/Makefile
--- linux-2.4.21-pre1/drivers/scsi/Makefile	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/scsi/Makefile	Wed Dec 18 14:16:28 2002
@@ -127,6 +127,7 @@
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
diff -urN linux-2.4.21-pre1/drivers/scsi/cpqfc.Readme linux-2.4.21-pre2/drivers/scsi/cpqfc.Readme
--- linux-2.4.21-pre1/drivers/scsi/cpqfc.Readme	Thu Oct 25 13:53:50 2001
+++ linux-2.4.21-pre2/drivers/scsi/cpqfc.Readme	Wed Dec 18 14:16:28 2002
@@ -22,6 +22,9 @@
    * Makefile changes to bring cpqfc into line w/ rest of SCSI drivers
      (thanks to Keith Owens)
 
+Ver 2.1.2  Jul 22, 2002
+   * initialize DumCmnd.lun (used as LUN index in fcFindLoggedInPort())
+
 Ver 2.0.5  Aug 06, 2001
    * Reject non-existent luns in the driver rather than letting the 
      hardware do it.  (some HW behaves differently than others in this area.)
diff -urN linux-2.4.21-pre1/drivers/scsi/cpqfcTSinit.c linux-2.4.21-pre2/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.21-pre1/drivers/scsi/cpqfcTSinit.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/cpqfcTSinit.c	Wed Dec 18 14:16:28 2002
@@ -64,7 +64,7 @@
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.1");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.2");
 MODULE_LICENSE("GPL");
 
 int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags);
@@ -242,6 +242,10 @@
 
 		while ((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) {
 
+			if (pci_enable_device(PciDev) != 0) {
+				printk(KERN_WARNING "cpqfc: pci_enable_devive failed, skipping.\n");
+				continue;
+			}
 			if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
 				printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n");
 				continue;
@@ -411,6 +415,7 @@
 	// can we find an FC device mapping to this SCSI target?
 	DumCmnd.channel = ScsiDev->channel;	// For searching
 	DumCmnd.target = ScsiDev->id;
+	DumCmnd.lun = ScsiDev->lun;
 	pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
 					   0,	// DON'T search linked list for FC port id
 					   NULL,	// DON'T search linked list for FC WWN
diff -urN linux-2.4.21-pre1/drivers/scsi/cpqfcTSstructs.h linux-2.4.21-pre2/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.21-pre1/drivers/scsi/cpqfcTSstructs.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/cpqfcTSstructs.h	Wed Dec 18 14:16:28 2002
@@ -35,7 +35,7 @@
 /* don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c */
 #define VER_MAJOR 2
 #define VER_MINOR 1
-#define VER_SUBMINOR 1
+#define VER_SUBMINOR 2
 
 /*
  *	Macros for kernel (esp. SMP) tracing using a PCI analyzer
diff -urN linux-2.4.21-pre1/drivers/scsi/cpqfcTSworker.c linux-2.4.21-pre2/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.21-pre1/drivers/scsi/cpqfcTSworker.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/cpqfcTSworker.c	Wed Dec 18 14:16:28 2002
@@ -2706,6 +2706,10 @@
 					// Report Luns command
 					if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
 						// we KNOW all the valid LUNs... 0xFF is invalid!
+						if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun)){
+							// printk("cpqfcTS FATAL: Invalid LUN index !!!!\n ");
+							return NULL;
+						}
 						Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
 						if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
 							return NULL;
diff -urN linux-2.4.21-pre1/drivers/scsi/gdth.c linux-2.4.21-pre2/drivers/scsi/gdth.c
--- linux-2.4.21-pre1/drivers/scsi/gdth.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/gdth.c	Wed Dec 18 14:16:28 2002
@@ -4143,6 +4143,9 @@
             break;
         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
+	    if(shp == NULL)
+		    continue;
+
             ha = HADATA(shp);
             if (!gdth_init_eisa(eisa_slot,ha)) {
                 scsi_unregister(shp);
diff -urN linux-2.4.21-pre1/drivers/scsi/in2000.c linux-2.4.21-pre2/drivers/scsi/in2000.c
--- linux-2.4.21-pre1/drivers/scsi/in2000.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.21-pre2/drivers/scsi/in2000.c	Wed Dec 18 14:16:28 2002
@@ -1916,14 +1916,14 @@
    0
    };
 
-static const unsigned short base_tab[] in2000__INITDATA = {
+static unsigned short base_tab[] in2000__INITDATA = {
    0x220,
    0x200,
    0x110,
    0x100,
    };
 
-static const int int_tab[] in2000__INITDATA = {
+static int int_tab[] in2000__INITDATA = {
    15,
    14,
    11,
diff -urN linux-2.4.21-pre1/drivers/scsi/megaraid.c linux-2.4.21-pre2/drivers/scsi/megaraid.c
--- linux-2.4.21-pre1/drivers/scsi/megaraid.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/megaraid.c	Wed Dec 18 14:16:28 2002
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : v1.18e (Nov 18, 2002)
+ * Version : v1.18f (Dec 10, 2002)
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -507,6 +507,10 @@
  *
  * remove an unsed variable
  *
+ * Version 1.18f
+ * Tue Dec 10 09:54:39 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * remove GFP_DMA flag for ioctl. This was causing overrun of DMA buffers.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -4869,7 +4873,7 @@
 		if(shpnt == NULL)  return -ENODEV;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -5015,7 +5019,7 @@
 		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -5379,8 +5383,6 @@
 		return rval;
 	}
 
-	printk("megaraid: logical drive %d deleted.\n", logdrv);
-
 	/*
 	 * After deleting first logical drive, the logical drives must be
 	 * addressed by adding 0x80 to the logical drive id.
diff -urN linux-2.4.21-pre1/drivers/scsi/megaraid.h linux-2.4.21-pre2/drivers/scsi/megaraid.h
--- linux-2.4.21-pre1/drivers/scsi/megaraid.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/megaraid.h	Wed Dec 18 14:16:28 2002
@@ -30,7 +30,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.18e (Release Date: Mon Nov 18 12:11:02 EST 2002)\n"
+#define MEGARAID_VERSION "v1.18f (Release Date: Tue Dec 10 09:54:39 EST 2002)\n"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
diff -urN linux-2.4.21-pre1/drivers/scsi/scsi_proc.c linux-2.4.21-pre2/drivers/scsi/scsi_proc.c
--- linux-2.4.21-pre1/drivers/scsi/scsi_proc.c	Wed Jun 27 17:10:55 2001
+++ linux-2.4.21-pre2/drivers/scsi/scsi_proc.c	Wed Dec 18 14:16:28 2002
@@ -308,22 +308,3 @@
 }
 
 #endif				/* CONFIG_PROC_FS */
-
-/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -urN linux-2.4.21-pre1/drivers/scsi/scsi_scan.c linux-2.4.21-pre2/drivers/scsi/scsi_scan.c
--- linux-2.4.21-pre1/drivers/scsi/scsi_scan.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/scsi/scsi_scan.c	Wed Dec 18 14:16:28 2002
@@ -162,7 +162,7 @@
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 530F
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},			/* HP XP Arrays */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP XP Arrays */
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN | BLIST_LARGELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G7324 RAID
 	{"CNSi", "G8324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G8324 RAID
diff -urN linux-2.4.21-pre1/drivers/sound/Config.in linux-2.4.21-pre2/drivers/sound/Config.in
--- linux-2.4.21-pre1/drivers/sound/Config.in	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/sound/Config.in	Wed Dec 18 14:16:28 2002
@@ -133,6 +133,7 @@
 
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '    AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS
+      dep_tristate '    AD1889 based cards (AD1819 codec) (EXPERIMENTAL)' CONFIG_SOUND_AD1889 $CONFIG_SOUND_OSS
    fi
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
    dep_tristate '    Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
diff -urN linux-2.4.21-pre1/drivers/sound/Makefile linux-2.4.21-pre2/drivers/sound/Makefile
--- linux-2.4.21-pre1/drivers/sound/Makefile	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/sound/Makefile	Wed Dec 18 14:16:28 2002
@@ -45,6 +45,7 @@
 obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_SGALAXY)	+= sgalaxy.o ad1848.o
 obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
+obj-$(CONFIG_SOUND_AD1889)      += ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
 
diff -urN linux-2.4.21-pre1/drivers/sound/ad1889.c linux-2.4.21-pre2/drivers/sound/ad1889.c
--- linux-2.4.21-pre1/drivers/sound/ad1889.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/sound/ad1889.c	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,1077 @@
+/*
+ *  Copyright 2001 Randolph Chung <tausq@debian.org>
+ *
+ *  Analog Devices 1889 PCI audio driver (AD1819 AC97-compatible codec)
+ *
+ *   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.
+ *
+ *   Notes:
+ *   1. Only flat DMA is supported; s-g is not supported right now
+ *
+ *
+<jsm> tausq: Anyway, to set up sample rates for D to A, you just use the sample rate on the codec. For A to D, you need to set the codec always to 48K (using the split sample rate feature on the codec) and then set the resampler on the AD1889 to the sample rate you want.
+<jsm> Also, when changing the sample rate on the codec you need to power it down and re power it up for the change to take effect!
+ *
+ * $Id: ad1889.c,v 1.2 2002/10/16 04:14:12 grundler Exp $
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/ac97_codec.h>
+#include <linux/sound.h>
+#include <linux/wrapper.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "ad1889.h"
+
+#define DBG(fmt, arg...) printk(fmt, ##arg)
+#define DEVNAME "ad1889"
+
+#define NR_HW_CH	4
+#define DAC_RUNNING	1
+#define ADC_RUNNING	2
+
+#define UNDERRUN(dev)	(0)
+
+#define AD1889_READW(dev,reg) readw(dev->regbase + reg)
+#define AD1889_WRITEW(dev,reg,val) writew((val), dev->regbase + reg)
+#define AD1889_READL(dev,reg) readl(dev->regbase + reg)
+#define AD1889_WRITEL(dev,reg,val) writel((val), dev->regbase + reg)
+
+//now 100ms
+#define WAIT_10MS()	do { int __i; for (__i = 0; __i < 100; __i++) udelay(1000); } while(0)
+
+/* currently only support a single device */
+static ad1889_dev_t *ad1889_dev = NULL;
+
+/************************* helper routines ***************************** */
+static inline void ad1889_set_wav_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_WAV_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSWAS, rate);
+}
+
+static inline void ad1889_set_adc_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_ADC_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSRES, rate);
+}
+
+static inline void ad1889_set_wav_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	if (fmt == AFMT_S16_LE) {
+		//tmp |= 0x0100; /* set WA16 */
+		tmp |= 0x0300; /* set WA16 stereo */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+}
+
+static inline void ad1889_set_adc_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (fmt == AFMT_S16_LE) {
+		tmp |= 0x0100; /* set WA16 */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+}
+
+static void ad1889_start_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int cnt;
+	u16 tmp;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->dma_len)	/* DMA already in flight */
+		goto skip_dma;
+
+	/* setup dma */
+	cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
+	if (cnt == 0)		/* done - don't need to do anything */
+		goto skip_dma;
+
+	/* If the wr_ptr has wrapped, only map to the end */
+	if (cnt < 0)
+		cnt = DMA_SIZE - dmabuf->rd_ptr;
+
+	dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
+					dmabuf->rawbuf + dmabuf->rd_ptr,
+					cnt, PCI_DMA_TODEVICE);
+	dmabuf->dma_len = cnt;
+	dmabuf->ready = 1;
+
+        /* load up the current register set */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVICC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCA, dmabuf->dma_handle);
+
+	/* TODO: for now we load the base registers with the same thing */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVIBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBA, dmabuf->dma_handle);
+
+	/* and we're off to the races... */
+	AD1889_WRITEL(ad1889_dev, AD_DMACHSS, 0x8);
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	tmp |= 0x0400; /* set WAEN */
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+	(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+
+	dmabuf->enable |= DAC_RUNNING;
+
+skip_dma:
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+static void ad1889_stop_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->enable & DAC_RUNNING) {
+		u16 tmp;
+		unsigned long cnt = dmabuf->dma_len;
+
+		tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+		tmp &= ~0x0400; /* clear WAEN */
+		AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+		(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+		pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle, 
+				cnt, PCI_DMA_TODEVICE);
+
+		dmabuf->enable &= ~DAC_RUNNING;
+
+		/* update dma pointers */
+		dmabuf->rd_ptr += cnt;
+		dmabuf->rd_ptr &= (DMA_SIZE - 1);
+
+		dmabuf->dma_handle = 0;
+		dmabuf->dma_len = 0;
+		dmabuf->ready = 0;
+
+		wake_up(&dmabuf->wait);
+	}
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+#if 0
+static void ad1889_startstop_adc(ad1889_state_t *state, int start)
+{
+	u16 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (start) {
+		state->dmabuf.enable |= ADC_RUNNING;
+		tmp |= 0x0004; /* set ADEN */
+	} else {
+		state->dmabuf.enable &= ~ADC_RUNNING;
+		tmp &= ~0x0004; /* clear ADEN */
+	}
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+#endif
+
+static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
+{
+	ad1889_dev_t *dev;
+	struct dmabuf *dmabuf;
+	int i;
+
+	if ((dev = kmalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL) 
+		return NULL;
+	memset(dev, 0, sizeof(ad1889_dev_t));
+	spin_lock_init(&dev->lock);
+	dev->pci = pci;
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dev->state[i].card = dev;
+		init_MUTEX(&dev->state[i].sem);
+		init_waitqueue_head(&dev->state[i].dmabuf.wait);
+	}
+
+	/* allocate dma buffer */
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dmabuf = &dev->state[i].dmabuf;
+		if ((dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA)) == NULL)
+			return NULL;
+		dmabuf->rawbuf_size = DMA_SIZE;
+		dmabuf->dma_handle = 0;
+		dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
+		dmabuf->ready = 0;
+		dmabuf->rate = 44100;
+	}
+
+	return dev;
+}
+
+static void ad1889_free_dev(ad1889_dev_t *dev)
+{
+	int j;
+	struct dmabuf *dmabuf;
+
+	if (dev == NULL) 
+		return;
+
+	if (dev->ac97_codec)
+		kfree(dev->ac97_codec);
+
+	for (j = 0; j < AD_MAX_STATES; j++) {
+		dmabuf = &dev->state[j].dmabuf;
+		if (dmabuf->rawbuf != NULL) 
+			kfree(dmabuf->rawbuf);
+	}
+
+	kfree(dev);
+}
+
+static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
+{
+#if 0
+	u32 val;
+	struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+#endif
+
+	ad1889_start_wav(&dev->state[AD_WAV_STATE]);
+}
+
+int ad1889_read_proc (char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	char *out = page;
+	int len, i;
+	ad1889_dev_t *dev = data;
+	ad1889_reg_t regs[] = {
+		{ "WSMC", AD_DSWSMC, 16 },
+		{ "RAMC", AD_DSRAMC, 16 },
+		{ "WADA", AD_DSWADA, 16 },
+		{ "SYDA", AD_DSSYDA, 16 },
+		{ "WAS", AD_DSWAS, 16 },
+		{ "RES", AD_DSRES, 16 },
+		{ "CCS", AD_DSCCS, 16 },
+		{ "ADCBA", AD_DMAADCBA, 32 },
+		{ "ADCCA", AD_DMAADCCA, 32 },
+		{ "ADCBC", AD_DMAADCBC, 32 },
+		{ "ADCCC", AD_DMAADCCC, 32 },
+		{ "ADCIBC", AD_DMAADCIBC, 32 },
+		{ "ADCICC", AD_DMAADCICC, 32 },
+		{ "ADCCTRL", AD_DMAADCCTRL, 16 },
+		{ "WAVBA", AD_DMAWAVBA, 32 },
+		{ "WAVCA", AD_DMAWAVCA, 32 },
+		{ "WAVBC", AD_DMAWAVBC, 32 },
+		{ "WAVCC", AD_DMAWAVCC, 32 },
+		{ "WAVIBC", AD_DMAWAVIBC, 32 },
+		{ "WAVICC", AD_DMAWAVICC, 32 },
+		{ "WAVCTRL", AD_DMAWAVCTRL, 16 },
+		{ "DISR", AD_DMADISR, 32 },
+		{ "CHSS", AD_DMACHSS, 32 },
+		{ "IPC", AD_GPIOIPC, 16 },
+		{ "OP", AD_GPIOOP, 16 },
+		{ "IP", AD_GPIOIP, 16 },
+		{ "ACIC", AD_ACIC, 16 },
+		{ "AC97_RESET", 0x100 + AC97_RESET, 16 },
+		{ "AC97_MASTER_VOL_STEREO", 0x100 + AC97_MASTER_VOL_STEREO, 16 },
+		{ "AC97_HEADPHONE_VOL", 0x100 + AC97_HEADPHONE_VOL, 16 },
+		{ "AC97_MASTER_VOL_MONO", 0x100 + AC97_MASTER_VOL_MONO, 16 },
+		{ "AC97_MASTER_TONE", 0x100 + AC97_MASTER_TONE, 16 },
+		{ "AC97_PCBEEP_VOL", 0x100 + AC97_PCBEEP_VOL, 16 },
+		{ "AC97_PHONE_VOL", 0x100 + AC97_PHONE_VOL, 16 },
+		{ "AC97_MIC_VOL", 0x100 + AC97_MIC_VOL, 16 },
+		{ "AC97_LINEIN_VOL", 0x100 + AC97_LINEIN_VOL, 16 },
+		{ "AC97_CD_VOL", 0x100 + AC97_CD_VOL, 16 },
+		{ "AC97_VIDEO_VOL", 0x100 + AC97_VIDEO_VOL, 16 },
+		{ "AC97_AUX_VOL", 0x100 + AC97_AUX_VOL, 16 },
+		{ "AC97_PCMOUT_VOL", 0x100 + AC97_PCMOUT_VOL, 16 },
+		{ "AC97_RECORD_SELECT", 0x100 + AC97_RECORD_SELECT, 16 },
+		{ "AC97_RECORD_GAIN", 0x100 + AC97_RECORD_GAIN, 16 },
+		{ "AC97_RECORD_GAIN_MIC", 0x100 + AC97_RECORD_GAIN_MIC, 16 },
+		{ "AC97_GENERAL_PURPOSE", 0x100 + AC97_GENERAL_PURPOSE, 16 },
+		{ "AC97_3D_CONTROL", 0x100 + AC97_3D_CONTROL, 16 },
+		{ "AC97_MODEM_RATE", 0x100 + AC97_MODEM_RATE, 16 },
+		{ "AC97_POWER_CONTROL", 0x100 + AC97_POWER_CONTROL, 16 },
+		{ 0 }
+	};
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	for (i = 0; regs[i].name != 0; i++)
+		out += sprintf(out, "%s: 0x%0*x\n", regs[i].name, 
+			regs[i].width >> 2, 
+			(regs[i].width == 16 
+			 	? AD1889_READW(dev, regs[i].offset)
+				: AD1889_READL(dev, regs[i].offset)));
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		out += sprintf(out, "DMA status for %s:\n", 
+			(i == AD_WAV_STATE ? "WAV" : "ADC")); 
+		out += sprintf(out, "\t\t0x%p (IOVA: 0x%u)\n", 
+			dev->state[i].dmabuf.rawbuf,
+			dev->state[i].dmabuf.dma_handle);
+
+		out += sprintf(out, "\tread ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.rd_ptr);
+		out += sprintf(out, "\twrite ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.wr_ptr);
+		out += sprintf(out, "\tdma len: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.dma_len);
+	}
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+/***************************** DMA interfaces ************************** */
+#if 0
+static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 offset;
+
+	if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
+		printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
+		return 0;
+	}
+	
+	if (dmabuf->enable & DAC_RUNNING)
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAWAVBA));
+	else
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAADCBA));
+
+	return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
+}
+
+static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
+{
+	ad1889_state_t *state;
+	struct dmabuf *dmabuf;
+	unsigned long hwptr;
+	int diff;
+
+	/* check ADC first */
+	state = &dev->adc_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & ADC_RUNNING) {
+		hwptr = ad1889_get_dma_addr(state);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize)
+			dmabuf->count = dmabuf->dmasize;
+
+		if (dmabuf->mapped) {
+			if (wake & dmabuf->count >= dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			if (wake & dmabuf->count > 0)
+				wake_up(&dmabuf->wait);
+		}
+	}
+
+	/* check DAC */
+	state = &dev->wav_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & DAC_RUNNING) {
+XXX
+
+}
+#endif
+
+/************************* /dev/dsp interfaces ************************* */
+
+static ssize_t ad1889_read(struct file *file, char *buffer, size_t count,
+	loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t ad1889_write(struct file *file, const char *buffer, size_t count,
+	loff_t *ppos)
+{
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = &dev->state[AD_WAV_STATE];
+	volatile struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	down(&state->sem);
+#if 0
+	if (dmabuf->mapped) {
+		ret = -ENXIO;
+		goto err1;
+	}
+#endif
+	if (!access_ok(VERIFY_READ, buffer, count)) {
+		ret = -EFAULT;
+		goto err1;
+	}
+
+	add_wait_queue(&state->dmabuf.wait, &wait);
+
+	/* start filling dma buffer.... */
+	while (count > 0) {
+		long rem;
+		long cnt = count;
+		unsigned long flags;
+
+
+		for (;;) {
+			long used_bytes;
+			long timeout;	/* max time for DMA in jiffies */
+
+			/* buffer is full if wr catches up to rd */
+			spin_lock_irqsave(&state->card->lock, flags);
+			used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
+			timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
+			spin_unlock_irqrestore(&state->card->lock, flags);
+
+			/* adjust for buffer wrap around */
+			used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
+
+			/* If at least one page unused */
+			if (used_bytes < (DMA_SIZE - 0x1000))
+				break;
+
+			/* dma buffer full */
+
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				goto err2;
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!schedule_timeout(timeout + 1))
+				printk(KERN_WARNING "AD1889 timeout(%ld) r/w %lx/%lx len %lx\n",
+				    timeout+1,
+				    dmabuf->rd_ptr, dmabuf->wr_ptr,
+				    dmabuf->dma_len);
+
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				goto err2;
+			}
+
+		}
+
+		/* watch out for wrapping around static buffer */
+		spin_lock_irqsave(&state->card->lock, flags);
+		rem = DMA_SIZE - dmabuf->wr_ptr;
+		if (cnt > rem)
+			cnt = rem;
+
+		rem = dmabuf->wr_ptr;
+
+		/* update dma pointers */
+		dmabuf->wr_ptr += cnt;
+		dmabuf->wr_ptr &= DMA_SIZE - 1;	/* wrap ptr if necessary */
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		/* transfer unwrapped chunk */
+		if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
+			ret = -EFAULT;
+			goto err2;
+		}
+
+		DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
+
+		/* update counters */
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		/* we have something to play - go play it! */
+		ad1889_trigger_playback(dev);
+	}
+
+err2:
+	remove_wait_queue(&state->dmabuf.wait, &wait);
+err1:
+	up(&state->sem);
+	return ret;
+}
+
+static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+#if 0
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = NULL;
+	struct dmabuf *dmabuf;
+	unsigned long flags;
+	
+	if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
+		return -EINVAL;
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[AD_WAV_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	ad1889_update_ptr(dev, 0);
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[WAV_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((int)dmabuf->dmasize >= dmabuf->count + 
+				(int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+
+	if (file ->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->count >= (int)dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+#endif
+	return mask;
+}
+
+static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int val = 0;
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	struct dmabuf *dmabuf;
+	audio_buf_info abinfo;
+
+	switch (cmd)
+	{
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		break;
+
+	case SNDCTL_DSP_SYNC:
+		break;
+
+	case SNDCTL_DSP_SPEED:
+		/* set sampling rate */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (val > 5400 && val < 48000)
+		{
+			if (file->f_mode & FMODE_WRITE)
+				AD1889_WRITEW(ad1889_dev, AD_DSWAS, val);
+			if (file->f_mode & FMODE_READ)
+				AD1889_WRITEW(ad1889_dev, AD_DSRES, val);
+		}
+		return 0;
+
+	case SNDCTL_DSP_STEREO: /* undocumented? */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			val = AD1889_READW(ad1889_dev, AD_DSWSMC);
+			if (val) {
+				val |= 0x0200;  /* set WAST */
+			} else {
+				val &= ~0x0200; /* clear WAST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSWSMC, val);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			val = AD1889_READW(ad1889_dev, AD_DSRAMC);
+			if (val) {
+				val |= 0x0002;  /* set ADST */
+			} else {
+				val &= ~0x0002; /* clear ADST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSRAMC, val);
+		}
+
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETFMTS:
+		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (file->f_mode & FMODE_READ) 
+			ad1889_set_adc_fmt(dev, val);
+
+		if (file->f_mode & FMODE_WRITE) 
+			ad1889_set_wav_fmt(dev, val);
+
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS:
+		break;
+
+	case SNDCTL_DSP_POST:
+		/* send all data to device */
+		break;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		break;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		/* not supported; uses fixed fragment sizes */
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETOSPACE:
+	case SNDCTL_DSP_GETISPACE:
+		/* space left in dma buffers */
+		if (cmd == SNDCTL_DSP_GETOSPACE)
+			dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+		else
+			dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
+		abinfo.fragments = 1;
+		abinfo.fragstotal = 1;
+		abinfo.fragsize = DMA_SIZE;
+		abinfo.bytes = DMA_SIZE;
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(0, (int *)arg);
+
+	case SNDCTL_DSP_GETTRIGGER:
+	case SNDCTL_DSP_SETTRIGGER:
+		break;
+
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+		break;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		break;
+	
+	case SNDCTL_DSP_GETODELAY:
+		break;
+
+	case SOUND_PCM_READ_RATE:
+		return put_user(AD1889_READW(ad1889_dev, AD_DSWAS), (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+	case SOUND_PCM_READ_BITS:
+		break;
+
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		break;
+
+	default:
+		break;
+	}
+
+	return -ENOTTY;
+}
+
+static int ad1889_open(struct inode *inode, struct file *file)
+{
+	/* check minor; only support /dev/dsp atm */
+	if (MINOR(inode->i_rdev) != 3)
+		return -ENXIO;
+	
+	file->private_data = ad1889_dev;
+
+	ad1889_set_wav_rate(ad1889_dev, 44100);
+	ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
+	AD1889_WRITEW(ad1889_dev, AD_DSWADA, 0x0404); /* attenuation */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_release(struct inode *inode, struct file *file)
+{
+	/* if we have state free it here */
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct file_operations ad1889_fops = {
+	llseek:         no_llseek,
+	read:           ad1889_read,
+	write:          ad1889_write,
+	poll:           ad1889_poll,
+	ioctl:          ad1889_ioctl,
+	mmap:           ad1889_mmap,
+	open:           ad1889_open,
+	release:        ad1889_release,
+};
+
+/************************* /dev/mixer interfaces ************************ */
+static int ad1889_mixer_open(struct inode *inode, struct file *file)
+{
+	if (ad1889_dev->ac97_codec->dev_mixer != MINOR(inode->i_rdev))
+		return -ENODEV;
+
+	file->private_data = ad1889_dev->ac97_codec;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_ioctl(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 struct file_operations ad1889_mixer_fops = {
+	llseek:         no_llseek,
+	ioctl:		ad1889_mixer_ioctl,
+	open:		ad1889_mixer_open,
+	release:	ad1889_mixer_release,
+};
+
+/************************* AC97 interfaces ****************************** */
+static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+
+	//DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + 0x100 + reg);
+	return AD1889_WRITEW(dev, 0x100 + reg, val);
+}
+
+static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+	//DBG("Reading from 0x%lx\n", dev->regbase + 0x100 + reg);
+	return AD1889_READW(dev, 0x100 + reg);
+}	
+
+static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
+{
+	struct ac97_codec *ac97;
+	u16 eid;
+
+	if ((ac97 = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) 
+		return -ENOMEM;
+	memset(ac97, 0, sizeof(struct ac97_codec));
+
+	ac97->private_data = dev;
+	ac97->id = id;
+
+	ac97->codec_read = ad1889_codec_read;
+	ac97->codec_write = ad1889_codec_write;
+
+	if (ac97_probe_codec(ac97) == 0) {
+		printk(DEVNAME ": ac97_probe_codec failed\n");
+		goto out_free;
+	}
+
+	eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
+	if (eid == 0xffffff) {
+		printk(KERN_WARNING DEVNAME ": no codec attached?\n");
+		goto out_free;
+	}
+
+	dev->ac97_features = eid;
+
+	if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register mixer\n");
+		goto out_free;
+	}
+
+	dev->ac97_codec = ac97;
+	return 0;
+
+out_free:
+	kfree(ac97);
+	return -ENODEV;
+}
+
+static int ad1889_aclink_reset(struct pci_dev * pcidev)
+{
+	u16 stat;
+	int retry = 200;
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	AD1889_WRITEW(dev, AD_DSCCS, 0x8000); /* turn on clock */
+	AD1889_READW(dev, AD_DSCCS); 
+
+	WAIT_10MS();
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0002;				/* Reset Disable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	(void) AD1889_READW(dev, AD_ACIC);	/* flush posted write */
+
+	udelay(10);
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0001;				/* Interface Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+
+	do {
+		if (AD1889_READW(dev, AD_ACIC) & 0x8000)	/* Ready */
+			break;
+		WAIT_10MS();
+		retry--;
+	} while (retry > 0);
+
+	if (!retry) {
+		printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
+			    AD1889_READW(dev, AD_ACIC));
+		return -EBUSY;
+	}
+
+	/* TODO reset AC97 codec */
+	/* TODO set wave/adc pci ctrl status */
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0004;				/* Audio Stream Output Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	return 0;
+}
+
+/************************* PCI interfaces ****************************** */
+/* PCI device table */
+static struct pci_device_id ad1889_id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID, 
+	  PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
+
+static void ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 stat;
+	ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
+
+	stat = AD1889_READL(dev, AD_DMADISR);
+
+	/* clear ISR */
+	AD1889_WRITEL(dev, AD_DMADISR, stat);
+
+	if (stat & 0x8) {		/* WAVI */
+		DBG("WAV interrupt\n");
+		dev->stats.wav_intrs++;
+		if (dev->state[AD_WAV_STATE].dmabuf.ready) {
+			ad1889_stop_wav(&dev->state[AD_WAV_STATE]);	/* clean up */
+			ad1889_start_wav(&dev->state[AD_WAV_STATE]);	/* start new */
+		}
+
+	}
+
+	if (stat & 0x2 && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
+		DBG("ADC interrupt\n");
+		dev->stats.adc_intrs++;
+	}
+}
+
+static void ad1889_initcfg(ad1889_dev_t *dev)
+{
+	u16 tmp;
+
+	/* make sure the interrupt bits are setup the way we want */
+	tmp = AD1889_READW(dev, AD_DMAWAVCTRL);
+	tmp &= ~0x00ff; /* flat dma, no sg, mask out the intr bits */
+	tmp |= 0x0004;  /* intr on count, loop */
+	AD1889_WRITEW(dev, AD_DMAWAVCTRL, tmp);
+
+	/* unmute... */
+	tmp = AD1889_READW(dev, AD_DSWADA);
+	tmp &= ~0x8080;
+	AD1889_WRITEW(dev, AD_DSWADA, tmp);
+}
+
+static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+	int err;
+	ad1889_dev_t *dev;
+	unsigned long bar;
+	struct proc_dir_entry *proc_root = NULL;
+
+	if ((err = pci_enable_device(pcidev)) != 0) {
+		printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
+		return err;
+	}
+
+	pci_set_master(pcidev);
+	if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
+		printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
+		return -ENOMEM;
+	}
+	pci_set_drvdata(pcidev, dev);
+	bar = pci_resource_start(pcidev, 0);
+	
+        if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR DEVNAME ": memory region not assigned\n");
+		goto err_free_mem;
+	}
+
+	if (request_irq(pcidev->irq, ad1889_interrupt, SA_SHIRQ, DEVNAME, dev) != 0) {
+		printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
+		goto err_free_mem;
+	}
+
+	request_mem_region(bar, AD_DSIOMEMSIZE, DEVNAME);
+	dev->regbase = (unsigned long)ioremap_nocache(bar, AD_DSIOMEMSIZE);
+
+	printk(KERN_INFO DEVNAME ": %s at 0x%lx IRQ %d\n",
+		(char *)ent->driver_data, dev->regbase, pcidev->irq);
+
+	if (ad1889_aclink_reset(pcidev) != 0)
+		goto err_free_mem;
+
+	/* register /dev/dsp */
+	if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
+		goto err_free_irq;
+	}
+
+	if ((err = ad1889_ac97_init(dev, 0)) != 0)
+		goto err_free_dsp;
+
+	if (((proc_root = proc_mkdir("driver/ad1889", 0)) == NULL) ||
+	    create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
+	    create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL) 
+		goto err_free_dsp;
+	
+	ad1889_initcfg(dev);
+
+	//DBG(DEVNAME ": Driver initialization done!\n");
+
+	ad1889_dev = dev;
+
+	return 0;
+
+err_free_dsp:
+	unregister_sound_dsp(dev->dev_audio);
+
+err_free_irq:
+	free_irq(pcidev->irq, dev);
+
+err_free_mem:
+	ad1889_free_dev(dev);
+	pci_set_drvdata(pcidev, 0);
+
+	return -ENODEV;
+}
+
+static void __devexit ad1889_remove(struct pci_dev *pcidev)
+{
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	if (dev == NULL) return;
+	
+	unregister_sound_mixer(dev->ac97_codec->dev_mixer);
+	unregister_sound_dsp(dev->dev_audio);
+	free_irq(pcidev->irq, dev);
+	release_mem_region(dev->regbase, AD_DSIOMEMSIZE);
+
+	/* any hw programming needed? */
+	ad1889_free_dev(dev);
+}
+
+MODULE_AUTHOR("Randolph Chung");
+MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
+MODULE_LICENSE("GPL");
+
+static struct pci_driver ad1889_driver = {
+	name:		DEVNAME,
+	id_table:	ad1889_id_tbl,
+	probe:		ad1889_probe,
+	remove:		ad1889_remove,
+};
+
+static int __init ad1889_init_module(void)
+{
+	return pci_module_init(&ad1889_driver);
+}
+
+static void ad1889_exit_module(void)
+{
+	pci_unregister_driver(&ad1889_driver);
+	return;
+}
+
+module_init(ad1889_init_module);
+module_exit(ad1889_exit_module);
diff -urN linux-2.4.21-pre1/drivers/sound/ad1889.h linux-2.4.21-pre2/drivers/sound/ad1889.h
--- linux-2.4.21-pre1/drivers/sound/ad1889.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/sound/ad1889.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,134 @@
+#ifndef _AD1889_H_
+#define _AD1889_H_
+
+#define AD_DSWSMC	0x00	/* DMA input wave/syn mixer control */
+#define AD_DSRAMC	0x02	/* DMA output resamp/ADC mixer control */
+#define AD_DSWADA	0x04	/* DMA input wave attenuation */
+#define AD_DSSYDA	0x06	/* DMA input syn attentuation */
+#define AD_DSWAS	0x08	/* wave input sample rate */
+#define AD_DSRES	0x0a	/* resampler output sample rate */
+#define AD_DSCCS	0x0c	/* chip control/status */
+
+#define AD_DMARESBA	0x40	/* RES base addr */
+#define AD_DMARESCA	0x44	/* RES current addr */
+#define AD_DMARESBC	0x48	/* RES base cnt */
+#define AD_DMARESCC	0x4c	/* RES current count */
+#define AD_DMAADCBA	0x50	/* ADC */
+#define AD_DMAADCCA	0x54
+#define AD_DMAADCBC	0x58
+#define AD_DMAADCCC	0x5c
+#define AD_DMASYNBA	0x60	/* SYN */
+#define AD_DMASYNCA	0x64
+#define AD_DMASYNBC	0x68
+#define AD_DMASYNCC	0x6c
+#define AD_DMAWAVBA	0x70	/* WAV */
+#define AD_DMAWAVCA	0x74
+#define AD_DMAWAVBC	0x78
+#define AD_DMAWAVCC	0x7c
+#define AD_DMARESICC	0x80	/* RES interrupt current count */
+#define AD_DMARESIBC	0x84	/* RES interrupt base count */
+#define AD_DMAADCICC	0x88	/* ADC interrupt current count */
+#define AD_DMAADCIBC	0x8c	/* ADC interrupt base count */
+#define AD_DMASYNICC	0x90	/* SYN interrupt current count */
+#define AD_DMASYNIBC	0x94	/* SYN interrupt base count */
+#define AD_DMAWAVICC	0x98	/* WAV interrupt current count */
+#define AD_DMAWAVIBC	0x9c	/* WAV interrupt base count */
+#define AD_DMARESCTRL	0xa0	/* RES PCI control/status */
+#define AD_DMAADCCTRL	0xa8	/* RES PCI control/status */
+#define AD_DMASYNCTRL	0xb0	/* RES PCI control/status */
+#define AD_DMAWAVCTRL	0xb8	/* RES PCI control/status */
+#define AD_DMADISR	0xc0	/* PCI DMA intr status */
+#define AD_DMACHSS	0xc4	/* PCI DMA channel stop status */
+
+#define AD_GPIOIPC	0xc8	/* IO port ctrl */
+#define AD_GPIOOP	0xca	/* IO output status */
+#define AD_GPIOIP	0xcc	/* IO input status */
+
+/* AC97 registers, 0x100 - 0x17f; see ac97.h */
+#define AD_ACIC		0x180	/* AC Link interface ctrl */
+
+/* OPL3; BAR1 */
+#define AD_OPLM0AS	0x00	/* Music0 address/status */
+#define AD_OPLM0DATA	0x01	/* Music0 data */
+#define AD_OPLM1A	0x02	/* Music1 address */
+#define AD_OPLM1DATA	0x03	/* Music1 data */
+/* 0x04-0x0f reserved */
+
+/* MIDI; BAR2 */
+#define AD_MIDA		0x00	/* MIDI data */
+#define AD_MISC		0x01	/* MIDI status/cmd */
+/* 0x02-0xff reserved */
+
+#define AD_DSIOMEMSIZE	512
+#define AD_OPLMEMSIZE	16
+#define AD_MIDIMEMSIZE	16
+
+#define AD_WAV_STATE	0
+#define AD_ADC_STATE	1
+#define AD_MAX_STATES	2
+
+#define DMA_SIZE	(128*1024)
+
+#define DMA_FLAG_MAPPED	1
+
+struct ad1889_dev;
+
+typedef struct ad1889_state {
+	struct ad1889_dev *card;
+
+	mode_t open_mode;
+	struct dmabuf {
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* buf management */
+		size_t rawbuf_size;
+		void *rawbuf;
+		dma_addr_t dma_handle;	/* mapped address */
+		unsigned long dma_len;	/* number of bytes mapped */
+
+		/* indexes into rawbuf for setting up DMA engine */
+		volatile unsigned long rd_ptr, wr_ptr;
+
+		wait_queue_head_t wait; /* to wait for buf servicing */
+
+		/* OSS bits */
+		unsigned int mapped:1;
+		unsigned int ready:1;
+		unsigned int ossfragshift;
+		int ossmaxfrags;
+		unsigned int subdivision;
+	} dmabuf;
+
+	struct semaphore sem;
+} ad1889_state_t;
+
+typedef struct ad1889_dev {
+	unsigned long regbase;
+	struct pci_dev *pci;
+	
+	spinlock_t lock;
+
+	int dev_audio;
+
+	/* states; one per channel; right now only WAV and ADC */
+	struct ad1889_state state[AD_MAX_STATES];
+
+	/* AC97 codec */
+	struct ac97_codec *ac97_codec;
+	u16 ac97_features;
+
+	/* debugging stuff */
+	struct stats {
+		unsigned int wav_intrs, adc_intrs;
+		unsigned int blocks, underrun, error;
+	} stats;
+} ad1889_dev_t;
+
+typedef struct ad1889_reg {
+	const char *name;
+	int offset;
+	int width;
+} ad1889_reg_t;
+
+#endif
diff -urN linux-2.4.21-pre1/drivers/sound/dmasound/dmasound_core.c linux-2.4.21-pre2/drivers/sound/dmasound/dmasound_core.c
--- linux-2.4.21-pre1/drivers/sound/dmasound/dmasound_core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.21-pre2/drivers/sound/dmasound/dmasound_core.c	Wed Dec 18 14:16:28 2002
@@ -1212,7 +1212,7 @@
 		return result ;
 		break ;
 	case SNDCTL_DSP_SPEED:
-		/* changing this on the fly will have wierd effects on the sound.
+		/* Changing this on the fly will have weird effects on the sound.
 		   Where there are rate conversions implemented in soft form - it
 		   will cause the _ctx_xxx() functions to be substituted.
 		   However, there doesn't appear to be any reason to dis-allow it from
diff -urN linux-2.4.21-pre1/drivers/sound/midibuf.c linux-2.4.21-pre2/drivers/sound/midibuf.c
--- linux-2.4.21-pre1/drivers/sound/midibuf.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.21-pre2/drivers/sound/midibuf.c	Wed Dec 18 14:16:28 2002
@@ -129,15 +129,16 @@
 		for (dev = 0; dev < num_midis; dev++)
 			if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
 			{
-				int ok = 1;
-
-				while (DATA_AVAIL(midi_out_buf[dev]) && ok)
+				while (DATA_AVAIL(midi_out_buf[dev]))
 				{
+					int ok;
 					int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
 
 					restore_flags(flags);	/* Give some time to others */
 					ok = midi_devs[dev]->outputc(dev, c);
 					cli();
+					if (!ok)
+						break;
 					midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
 					midi_out_buf[dev]->len--;
 				}
diff -urN linux-2.4.21-pre1/drivers/usb/Config.in linux-2.4.21-pre2/drivers/usb/Config.in
--- linux-2.4.21-pre1/drivers/usb/Config.in	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/usb/Config.in	Wed Dec 18 14:16:28 2002
@@ -15,7 +15,6 @@
    else
       define_bool CONFIG_USB_BANDWIDTH n
    fi
-   bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
 
    comment 'USB Host Controller Drivers'
    source drivers/usb/hcd/Config.in
@@ -101,7 +100,7 @@
       dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-      dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    fi
 
    comment 'USB port drivers'
diff -urN linux-2.4.21-pre1/drivers/usb/hc_sl811.c linux-2.4.21-pre2/drivers/usb/hc_sl811.c
--- linux-2.4.21-pre1/drivers/usb/hc_sl811.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/hc_sl811.c	Wed Dec 18 14:16:28 2002
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
diff -urN linux-2.4.21-pre1/drivers/usb/pegasus.c linux-2.4.21-pre2/drivers/usb/pegasus.c
--- linux-2.4.21-pre1/drivers/usb/pegasus.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/usb/pegasus.c	Wed Dec 18 14:16:28 2002
@@ -42,7 +42,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.27 (2002/11/19)"
+#define DRIVER_VERSION "v0.4.28 (2002/12/13)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -116,9 +116,14 @@
 			 void *data)
 {
 	int ret;
-	unsigned char buffer[256];
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
+	buffer = kmalloc(size, GFP_DMA);
+	if (!buffer) {
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -150,6 +155,7 @@
 out:
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	memcpy(data, buffer, size);
+	kfree(buffer);
 
 	return ret;
 }
@@ -158,9 +164,14 @@
 			 void *data)
 {
 	int ret;
-	unsigned char buffer[256];
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
+	buffer = kmalloc(size, GFP_DMA);
+	if (!buffer) {
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
 	memcpy(buffer, data, size);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
@@ -193,6 +204,7 @@
 	schedule();
 out:
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	kfree(buffer);
 
 	return ret;
 }
@@ -200,9 +212,15 @@
 static int set_register(pegasus_t * pegasus, u16 indx, u8 data)
 {
 	int ret;
-	u16 tmp = data;
+	char *tmp;
 	DECLARE_WAITQUEUE(wait, current);
 
+	tmp = kmalloc(1, GFP_DMA);
+	if (!tmp) {
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	memcpy(tmp, &data, 1);
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -212,7 +230,7 @@
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
-	pegasus->dr.wValue = cpu_to_le16p(&tmp);
+	pegasus->dr.wValue = cpu_to_le16p(&data);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16(1);
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
@@ -220,7 +238,7 @@
 	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
 			 usb_sndctrlpipe(pegasus->usb, 0),
 			 (char *) &pegasus->dr,
-			 &data, 1, ctrl_callback, pegasus);
+			 tmp, 1, ctrl_callback, pegasus);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
@@ -233,6 +251,7 @@
 	schedule();
 out:
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	kfree(tmp);
 
 	return ret;
 }
diff -urN linux-2.4.21-pre1/drivers/usb/pwc-ctrl.c linux-2.4.21-pre2/drivers/usb/pwc-ctrl.c
--- linux-2.4.21-pre1/drivers/usb/pwc-ctrl.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/drivers/usb/pwc-ctrl.c	Wed Dec 18 14:16:28 2002
@@ -256,8 +256,10 @@
 
 	memcpy(buf, pEntry->mode, 3);	
 	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
-	if (ret < 0)
+	if (ret < 0) {
+		Debug("Failed to send video command... %d\n", ret);
 		return ret;
+	}
 	if (pEntry->compressed && pdev->decompressor != NULL)
 		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
@@ -444,8 +446,8 @@
 			Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
 		else {
 			Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-			return ret;
 		}
+		return ret;
 	}
 	pdev->view.x = width;
 	pdev->view.y = height;
@@ -997,7 +999,7 @@
 		&buf, 1, HZ / 2);
 
 	if (ret < 0)
-	    return ret;
+		return ret;
 	
 	return (buf << 8);
 }
@@ -1103,12 +1105,7 @@
 	buf[0] = on_value;
 	buf[1] = off_value;
 
-	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
-		SET_STATUS_CTL,
-		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
+	return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
 }
 
 int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
@@ -1122,13 +1119,7 @@
 		return 0;
 	}
 
-	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-   	        GET_STATUS_CTL,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
-
+	ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
 	if (ret < 0)
 		return ret;
 	*on_value = buf[0] * 100;
@@ -1252,7 +1243,7 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
 	return buf;
@@ -1276,10 +1267,9 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-Debug("pwc_get_dynamic_noise = %d\n", buf);
 	return buf;
 }
 
@@ -1595,6 +1585,16 @@
 		break;
 	}
 	
+	case VIDIOCPWCGREALSIZE:
+	{
+		struct pwc_imagesize size;
+		
+		size.width = pdev->image.x;
+		size.height = pdev->image.y;
+		if (copy_to_user(arg, &size, sizeof(size)))
+			ret = -EFAULT;
+		break;
+	}	
 
 	default:
 		ret = -ENOIOCTLCMD;
diff -urN linux-2.4.21-pre1/drivers/usb/pwc-if.c linux-2.4.21-pre2/drivers/usb/pwc-if.c
--- linux-2.4.21-pre1/drivers/usb/pwc-if.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/pwc-if.c	Wed Dec 18 14:16:28 2002
@@ -42,11 +42,15 @@
    - Alistar Moire: QuickCam 3000 Pro device/product ID
    - Tony Hoyle: Creative Labs Webcam 5 device/product ID
    - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
-   - Jk Fang: SOTEC device/product ID
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
 */
 
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
@@ -58,10 +62,6 @@
 #include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 
-#if !defined(MAP_NR)
-#define MAP_NR(a) virt_to_page(a)
-#endif
-
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
@@ -76,10 +76,13 @@
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */
+	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
+	{ USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam Notebook Pro */
+	{ USB_DEVICE(0x046d, 0x08b2) }, /* Logitech QuickCam Pro 4000 */
+	{ USB_DEVICE(0x046d, 0x08b3) }, /* Logitech QuickCam Zoom */
 	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
 	{ USB_DEVICE(0x055D, 0x9001) },
-	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative */
+	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
 	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
 	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
 	{ USB_DEVICE(0x0d81, 0x1900) },
@@ -127,7 +130,7 @@
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);
+static int  pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size);
 
 static struct video_device pwc_template = {
 	owner:		THIS_MODULE,
@@ -238,7 +241,7 @@
 	int i;
 	void *kbuf;
 
-	Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev);
+	Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
 	if (pdev == NULL)
 		return -ENXIO;
@@ -315,7 +318,7 @@
 
 	kbuf = NULL;
 	  
-	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
+	Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
 	return 0;
 }
 
@@ -612,7 +615,7 @@
 	}
 #endif
 	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n");
+		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -685,9 +688,22 @@
 #if PWC_DEBUG
 							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
 #endif
-							pdev->drop_frames = 2;
+							pdev->drop_frames += 2;
 							pdev->vframes_error++;
 						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+							if (ptr[0] & 0x01)
+								Info("Snapshot button pressed.\n");
+							else
+								Info("Snapshot button released.\n");
+						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+							if (ptr[0] & 0x02)
+								Info("Image is mirrored.\n");
+							else
+								Info("Image is normal.\n");
+						}
+						pdev->vmirror = ptr[0] & 0x03;
 						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
 						   after a short frame; this condition is filtered out specifically. A 4 byte
 						   frame doesn't make sense anyway.
@@ -704,7 +720,7 @@
 					/* In case we were instructed to drop the frame, do so silently.
 					   The buffer pointers are not updated either (but the counters are reset below).
 					 */
-					if (pdev->drop_frames)
+					if (pdev->drop_frames > 0)
 						pdev->drop_frames--;
 					else {
 						/* Check for underflow first */
@@ -740,10 +756,14 @@
 			} /* .. flen < last_packet_size */
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
-#ifdef PWC_DEBUG
+#if PWC_DEBUG
 		/* This is normally not interesting to the user, unless you are really debugging something */
-		else 
-			Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		else {
+			static int iso_error = 0;
+			iso_error++;
+			if (iso_error < 20)
+				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		}
 #endif			
 	}
 	if (awake)
@@ -758,7 +778,6 @@
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
-	int cur_alt;
 
 	if (pdev == NULL)
 		return -EFAULT;
@@ -766,12 +785,11 @@
 		return 0;
 	pdev->vsync = 0;
 	udev = pdev->udev;
-	
+
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 		return -EFAULT;
-	cur_alt = udev->actconfig->interface[0].act_altsetting;
-	idesc = &udev->actconfig->interface[0].altsetting[cur_alt];
+	idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate];
 	if (!idesc)
 		return -EFAULT;
 
@@ -783,12 +801,18 @@
 			break;
 		}
 	
-	if (pdev->vmax_packet_size < 0) {
+	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
 		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
 		return -ENFILE; /* Odd error, that should be noticable */
 	}
 
+	/* Set alternate interface */
 	ret = 0;
+	Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+	if (ret < 0)
+		return ret;
+
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC);
 		if (urb == NULL) {
@@ -797,6 +821,7 @@
 			break;
 		}
 		pdev->sbuf[i].urb = urb;
+		Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
 	}
 	if (ret) {
 		/* De-allocate in reverse order */
@@ -808,8 +833,7 @@
 		}
 		return ret;
 	}
-	
-	
+
 	/* init URB structure */	
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = pdev->sbuf[i].urb;
@@ -826,7 +850,7 @@
 		urb->number_of_packets = ISO_FRAMES_PER_DESC;
 		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
 			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
 		}
 	}
 
@@ -836,11 +860,12 @@
 		if (ret)
 			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
 		else
-			Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");
+			Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
 	}
 
-	/* data should stream in now */
+	/* All is done... */
 	pdev->iso_init = 1;
+	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
 	return 0;
 }
 
@@ -848,21 +873,34 @@
 {
 	int i;
 	
+	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
 	if (pdev == NULL)
 		return;
-	if (!pdev->iso_init)
-		return;
+
+	/* Unlinking ISOC buffers one by one */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = pdev->sbuf[i].urb;
+		if (urb != 0) {
+			if (pdev->iso_init) {
+				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+				usb_unlink_urb(urb);
+			}
+			Trace(TRACE_MEMORY, "Freeing URB\n");
+			usb_free_urb(urb);
+			pdev->sbuf[i].urb = NULL;
+		}
+	}
+
 	/* Stop camera, but only if we are sure the camera is still there */
-	if (!pdev->unplugged)
+	if (!pdev->unplugged) {
+		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
-	/* Unlinking ISOC buffers one by one */
-	for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {
-		pdev->sbuf[i].urb->next = NULL;
-		usb_unlink_urb(pdev->sbuf[i].urb);
-		usb_free_urb(pdev->sbuf[i].urb);
-		pdev->sbuf[i].urb = NULL;
 	}
+
 	pdev->iso_init = 0;
+	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -876,11 +914,10 @@
 	ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
 	if (ret) /* That failed... restore old mode (we know that worked) */
 		ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-	else /* Set (new) alternate interface */
-		ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
 	if (!ret)
-		ret = pwc_isoc_init(pdev);
-	pdev->drop_frames = 1; /* try to avoid garbage during switch */
+		if (pwc_isoc_init(pdev) < 0)
+			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+	pdev->drop_frames++; /* try to avoid garbage during switch */
 	return ret;
 }
 
@@ -915,20 +952,19 @@
 	int i;
 	struct pwc_device *pdev;
 
-	Trace(TRACE_OPEN, "video_open called(0x%p, 0%o).\n", vdev, mode);
+	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
 	
 	if (vdev == NULL)
 		BUG();
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev == NULL)
 		BUG();
+	if (pdev->vopen)
+		return -EBUSY;
 	
 	down(&pdev->modlock);
 	if (!pdev->usb_init) {
 		Trace(TRACE_OPEN, "Doing first time initialization.\n");
-		/* Reset camera */
-		if (usb_set_interface(pdev->udev, 0, 0))
-			Info("Failed to set alternate interface to 0.\n");
 		pdev->usb_init = 1;
 		
 		if (pwc_trace & TRACE_OPEN) {
@@ -948,10 +984,10 @@
 			case 0x40:  sensor_type = "UPA 1021 sensor"; break;
 			case 0x100: sensor_type = "VGA sensor"; break;
 			case 0x101: sensor_type = "PAL MR sensor"; break;
-			default:   sensor_type = "unknown type of sensor"; break;
+			default:    sensor_type = "unknown type of sensor"; break;
 			}
 			if (sensor_type != NULL)
-				Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
 		}
 	}
 
@@ -1017,16 +1053,9 @@
 		return i;
 	}
 	
-	i = usb_set_interface(pdev->udev, 0, pdev->valternate);
-	if (i) {
-		Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);
-		up(&pdev->modlock);
-		return -EINVAL;
-	}
 	i = pwc_isoc_init(pdev);
 	if (i) {
 		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
-		MOD_DEC_USE_COUNT;
 		up(&pdev->modlock);
 		return i;
 	}
@@ -1039,7 +1068,7 @@
 	if (pdev->decompressor != NULL)
 		pdev->decompressor->lock();
 	up(&pdev->modlock);
-	Trace(TRACE_OPEN, "video_open() returning 0.\n");
+	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
 	return 0;
 }
 
@@ -1049,15 +1078,12 @@
 	struct pwc_device *pdev;
 	int i;
 
-	Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev);
+	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
 
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev->vopen == 0)
 		Info("video_close() called on closed device?\n");
 
-	/* Free isoc URBs */
-	pwc_isoc_cleanup(pdev);
-
 	/* Dump statistics, but only if a reasonable amount of frames were
 	   processed (to prevent endless log-entries in case of snap-shot
 	   programs) 
@@ -1065,21 +1091,14 @@
 	if (pdev->vframe_count > 20)
 		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-	if (pdev->unplugged) {
-		/* The device was unplugged or some other error occured */
-		/* We unregister the video_device */
-		Trace(TRACE_OPEN, "Delayed video device unregistered.\n");
-		video_unregister_device(pdev->vdev);
-	}
-	else {
-		/* Normal close: stop isochronuous and interrupt endpoint */
-		Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
-		usb_set_interface(pdev->udev, 0, 0);
+	/* Free isoc URBs, stop camera */
+	pwc_isoc_cleanup(pdev);
 
+	if (!pdev->unplugged) {
 		/* Turn LEDs off */
 		if (pwc_set_leds(pdev, 0, 0) < 0)
-			Info("Failed to set LED on/off time..\n");
-		/* Power down camere to save energy */
+			Info("Failed to set LED on/off time.\n");
+		/* Power down camera to save energy */
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0) 
@@ -1097,6 +1116,7 @@
 	/* wake up _disconnect() routine */
 	if (pdev->unplugged)
 		wake_up(&pdev->remove_ok);
+	Trace(TRACE_OPEN, "<< video_close()\n");
 }
 
 /*
@@ -1131,6 +1151,7 @@
 	if (pdev->image_read_pos == 0) {
 		/* Do wait queueing according to the (doc)book */
 		add_wait_queue(&pdev->frameq, &wait);
+	        set_current_state(TASK_INTERRUPTIBLE);
 		while (pdev->full_frames == NULL) {
 	                if (noblock) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
@@ -1483,6 +1504,7 @@
 			            frameq is safe now.
 			 */
 			add_wait_queue(&pdev->frameq, &wait);
+		        set_current_state(TASK_INTERRUPTIBLE);
 			while (pdev->full_frames == NULL) {
 				if (pdev->unplugged) {
 					remove_wait_queue(&pdev->frameq, &wait);
@@ -1495,8 +1517,8 @@
 		                	set_current_state(TASK_RUNNING);
 		                	return -ERESTARTSYS;
 	        	        }
-	                	schedule();
 		                set_current_state(TASK_INTERRUPTIBLE);
+	                	schedule();
 			}
 			remove_wait_queue(&pdev->frameq, &wait);
 			set_current_state(TASK_RUNNING);
@@ -1574,8 +1596,6 @@
 	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size);
 	pdev = vdev->priv;
 
-	/* FIXME - audit mmap during a read */		
-	/* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1691,10 +1711,25 @@
 	else if (vendor_id == 0x046d) {
 		switch(product_id) {
 		case 0x08b0:
-			Info("Logitech QuickCam 3000 Pro USB webcam detected.\n");
-			name = "Logitech QuickCam 3000 Pro";
+			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 3000";
 			type_id = 730;
-        		break;
+			break;
+		case 0x08b1:
+			Info("Logitech QuickCam for Notebook Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Notebook Pro";
+			type_id = 740; /* ?? unknown sensor */
+			break;
+		case 0x08b2:
+			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 4000";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b3:
+			Info("Logitech QuickCam Zoom USB webcam detected.\n");
+			name = "Logitech QuickCam Zoom";
+			type_id = 740; /* CCD sensor */
+			break;
         	default:
         		return NULL;
         		break;
@@ -1868,6 +1903,10 @@
 	
 	pdev->unplugged = 1;
 	if (pdev->vdev != NULL) {
+		add_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		Trace(TRACE_PROBE, "Unregistering video device.\n");
+		video_unregister_device(pdev->vdev); 
 		if (pdev->vopen) {
 			Info("Disconnected while device/video is open!\n");
 			
@@ -1883,23 +1922,19 @@
 			 */
 			   
 			Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
-			add_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_UNINTERRUPTIBLE);
 			/* ... wait ... */
 			schedule();
-			remove_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_RUNNING);
 			Trace(TRACE_PROBE, "Done sleeping.\n");
 			set_mem_leak(pdev->vdev);
 			pdev->vdev = NULL;
 		}
 		else {
 			/* Normal disconnect; remove from available devices */
-			Trace(TRACE_PROBE, "Unregistering video device normally.\n");
-			video_unregister_device(pdev->vdev); 
 			kfree(pdev->vdev);
 			pdev->vdev = NULL;
 		}
+		remove_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_RUNNING);
 	}
 
 	/* search device_hint[] table if we occupy a slot, by any chance */
@@ -1914,7 +1949,7 @@
 
 
 /* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(char *s)
+static int pwc_atoi(const char *s)
 {
 	int k = 0;
 	
@@ -1959,7 +1994,7 @@
 MODULE_PARM(dev_hint, "0-10s");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
-MODULE_DESCRIPTION("Philips USB webcam driver");
+MODULE_DESCRIPTION("Philips USB & OEM webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
@@ -1969,7 +2004,7 @@
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
-	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n");
+	Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
 	Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
 	if (fps) {
@@ -2087,7 +2122,7 @@
 					device_hint[i].serial_number[k] = '\0';
 				}
 			}
-#ifdef PWC_DEBUG		
+#if PWC_DEBUG		
 			Debug("device_hint[%d]:\n", i);
 			Debug("  type    : %d\n", device_hint[i].type);
 			Debug("  serial# : %s\n", device_hint[i].serial_number);
diff -urN linux-2.4.21-pre1/drivers/usb/pwc-ioctl.h linux-2.4.21-pre2/drivers/usb/pwc-ioctl.h
--- linux-2.4.21-pre1/drivers/usb/pwc-ioctl.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/drivers/usb/pwc-ioctl.h	Wed Dec 18 14:16:28 2002
@@ -18,12 +18,13 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*         This is pwc-ioctl.h belonging to PWC 8.6                        */
+/*         This is pwc-ioctl.h belonging to PWC 8.10                        */
 
 /* 
    Changes
    2001/08/03  Alvarado   Added ioctl constants to access methods for 
                           changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
  */
 
 /* These are private ioctl() commands, specific for the Philips webcams.
@@ -104,7 +105,12 @@
 	int led_off;			/* Led off-time; range = 0..25000  */
 };
 
-
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
 
  /* Restore user settings */
 #define VIDIOCPWCRUSER		_IO('v', 192)
@@ -173,4 +179,7 @@
 #define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
 #define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
 
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+ 
 #endif
diff -urN linux-2.4.21-pre1/drivers/usb/pwc-uncompress.c linux-2.4.21-pre2/drivers/usb/pwc-uncompress.c
--- linux-2.4.21-pre1/drivers/usb/pwc-uncompress.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/drivers/usb/pwc-uncompress.c	Wed Dec 18 14:16:28 2002
@@ -77,7 +77,7 @@
 {
 	struct pwc_frame_buf *fbuf;
 	int n, line, col, stride;
-	void *yuv, *image, *dst;
+	void *yuv, *image;
 	u16 *src;
 	u16 *dsty, *dstu, *dstv;
 
@@ -114,19 +114,6 @@
 		   to get the desired output format/size.
 		 */
 		switch (pdev->vpalette) {
-		case VIDEO_PALETTE_YUV420:
-			/* Calculate byte offsets per line in image & view */
-			n   = (pdev->image.x * 3) / 2;
-			col = (pdev->view.x  * 3) / 2;
-			/* Offset into image */
-			dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2;
-			for (line = 0; line < pdev->image.y; line++) {
-				memcpy(dst, yuv, n);
-				yuv += n;
-				dst += col;
-			}
-			break;
-
 		case VIDEO_PALETTE_YUV420P:
 			/* 
 			 * We do some byte shuffling here to go from the 
@@ -163,17 +150,20 @@
 					dstu += (stride >> 1);
 			}
 			break;
+		default:
+			Err("Unsupported palette!");
+			break;
 		}
 	}
 	else { 
 		/* Compressed; the decompressor routines will write the data 
-		   in interlaced or planar format immediately.
+		   in planar format immediately.
 		 */
 		if (pdev->decompressor)
 			pdev->decompressor->decompress(
 				&pdev->image, &pdev->view, &pdev->offset,
-				yuv, image, 
-				pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0,
+				yuv, image,
+				1,
 				pdev->decompress_data, pdev->vbandlength);
 		else
 			return -ENXIO; /* No such device or address: missing decompressor */
diff -urN linux-2.4.21-pre1/drivers/usb/pwc.h linux-2.4.21-pre2/drivers/usb/pwc.h
--- linux-2.4.21-pre1/drivers/usb/pwc.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/drivers/usb/pwc.h	Wed Dec 18 14:16:28 2002
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	6
-#define PWC_VERSION 	"8.6"
+#define PWC_MINOR	10
+#define PWC_VERSION 	"8.10"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -130,7 +130,7 @@
    int vcinterface;		/* video control interface */
    int valternate;		/* alternate interface needed */
    int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
-   int vpalette;		/* YUV, RGB24, RGB32, etc */
+   int vpalette;		/* YUV */
    int vframe_count;		/* received frames */
    int vframes_dumped; 		/* counter for dumped frames */
    int vframes_error;		/* frames received in error */
@@ -140,7 +140,8 @@
    int vbandlength;		/* compressed band length; 0 is uncompressed */
    char vsnapshot;		/* snapshot mode */
    char vsync;			/* used by isoc handler */
-   
+   char vmirror;		/* for ToUCaM series */
+
    /* The image acquisition requires 3 to 4 steps:
       1. data is gathered in short packets from the USB controller
       2. data is synchronized and packed into a frame buffer
diff -urN linux-2.4.21-pre1/drivers/usb/rtl8150.c linux-2.4.21-pre2/drivers/usb/rtl8150.c
--- linux-2.4.21-pre1/drivers/usb/rtl8150.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/usb/rtl8150.c	Wed Dec 18 14:16:28 2002
@@ -18,15 +18,14 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
-#include <linux/init.h>
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.4.1 (2002/07/22)"
+#define DRIVER_VERSION "v0.4.2 (2002/09/19)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
-#define	IRD			0x0120
+#define	IDR			0x0120
 #define	MAR			0x0126
 #define	CR			0x012e
 #define	TCR			0x012f
@@ -46,6 +45,8 @@
 #define	ANLP			0x0146
 #define	AER			0x0148
 
+#define	IDR_EEPROM		0x1202
+
 #define	PHY_READ		0
 #define	PHY_WRITE		0x20
 #define	PHY_GO			0x40
@@ -72,6 +73,8 @@
 #define PRODUCT_ID_RTL8150		0x8150
 #define	PRODUCT_ID_LUAKTX		0x0012
 
+#undef EEPROM_WRITE
+
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8150_table[] = {
 	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
@@ -226,10 +229,51 @@
 {
 	u8 node_id[6];
 
-	get_registers(dev, IRD, sizeof(node_id), node_id);
+	get_registers(dev, IDR, sizeof(node_id), node_id);
 	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
 }
 
+static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
+{
+	struct sockaddr *addr = p;
+	rtl8150_t *dev;
+	int i;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+	dev = netdev->priv;
+	if (dev == NULL) {
+		return -ENODEV;
+	}
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	dbg("%s: Setting MAC address to ", netdev->name);
+	for (i = 0; i < 5; i++)
+		printk("%02X:", netdev->dev_addr[i]);
+	dbg("%02X\n", netdev->dev_addr[i]);
+	/* Set the IDR registers. */
+	set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr);
+#ifdef EEPROM_WRITE
+	{
+	u8 cr;
+	/* Get the CR contents. */
+	get_registers(dev, CR, 1, &cr);
+	/* Set the WEPROM bit (eeprom write enable). */
+	cr |= 0x20;
+	set_registers(dev, CR, 1, &cr);
+	/* Write the MAC address into eeprom. Eeprom writes must be word-sized,
+	   so we need to split them up. */
+	for (i = 0; i * 2 < netdev->addr_len; i++) {
+		set_registers(dev, IDR_EEPROM + (i * 2), 2, 
+		              netdev->dev_addr + (i * 2));
+	}
+	/* Clear the WEPROM bit (preventing accidental eeprom writes). */
+	cr &= 0xdf;
+	set_registers(dev, CR, 1, &cr);
+	}
+#endif	
+	return 0;
+}
+
 static int rtl8150_reset(rtl8150_t * dev)
 {
 	u8 data = 0x10;
@@ -667,6 +711,7 @@
 	netdev->tx_timeout = rtl8150_tx_timeout;
 	netdev->hard_start_xmit = rtl8150_start_xmit;
 	netdev->set_multicast_list = rtl8150_set_multicast;
+	netdev->set_mac_address = rtl8150_set_mac_address;
 	netdev->get_stats = rtl8150_netdev_stats;
 	netdev->mtu = RTL8150_MTU;
 	dev->intr_interval = 100;	/* 100ms */
diff -urN linux-2.4.21-pre1/drivers/usb/serial/Config.in linux-2.4.21-pre2/drivers/usb/serial/Config.in
--- linux-2.4.21-pre1/drivers/usb/serial/Config.in	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/serial/Config.in	Wed Dec 18 14:16:28 2002
@@ -34,6 +34,7 @@
    fi
    dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
    dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL
+   dep_tristate '  USB KOBIL chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_KOBIL_SCT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
    dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -urN linux-2.4.21-pre1/drivers/usb/serial/Makefile linux-2.4.21-pre2/drivers/usb/serial/Makefile
--- linux-2.4.21-pre1/drivers/usb/serial/Makefile	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/serial/Makefile	Wed Dec 18 14:16:28 2002
@@ -25,6 +25,7 @@
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
+obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -urN linux-2.4.21-pre1/drivers/usb/serial/ftdi_sio.c linux-2.4.21-pre2/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.21-pre1/drivers/usb/serial/ftdi_sio.c	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/serial/ftdi_sio.c	Wed Dec 18 14:16:28 2002
@@ -17,6 +17,14 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (07/Jun/2002) Kuba Ober
+ *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ *	function. It was getting too complex.
+ *	Fix the divisor calculation logic which was setting divisor of 0.125
+ *	instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+ *	Also make it bump up the divisor to next integer in case of 7/8 - it's
+ *	a better approximation.
+ *
  * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
  *      Not tested by me but it doesn't break anything I use.
  * 
@@ -203,6 +211,10 @@
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
+static unsigned short int ftdi_baud_base_to_divisor
+					(int baud, int base);
+static unsigned short int ftdi_baud_to_divisor
+					(int baud);
 
 static struct usb_serial_device_type ftdi_SIO_device = {
 	.owner =		THIS_MODULE,
@@ -257,6 +269,23 @@
  * ***************************************************************************
  */
 
+static unsigned short int ftdi_baud_base_to_divisor(int baud, int base)
+{
+	unsigned short int divisor;
+	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+	if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+	divisor = divisor3 >> 3;
+	divisor3 &= 0x7;
+	if (divisor3 == 1) divisor |= 0xc000; else // 0.125
+	if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
+	if (divisor3 != 0) divisor |= 0x8000;      // 0.25
+	return divisor;
+}
+
+static unsigned short int ftdi_baud_to_divisor(int baud)
+{
+	 return(ftdi_baud_base_to_divisor(baud, 48000000));
+}
 
 static int set_rts(struct usb_device *dev,
 		   unsigned int pipe,
@@ -373,7 +402,7 @@
 		break;
 	case FT8U232AM: /* 8U232AM chip */
 		if (baud <= 3000000) {
-			urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+			urb_value = ftdi_baud_to_divisor(baud);
 		} else {
 	                dbg("%s - Baud rate too high!", __FUNCTION__);
 		}
diff -urN linux-2.4.21-pre1/drivers/usb/serial/ftdi_sio.h linux-2.4.21-pre2/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.21-pre1/drivers/usb/serial/ftdi_sio.h	Thu Nov 28 15:53:14 2002
+++ linux-2.4.21-pre2/drivers/usb/serial/ftdi_sio.h	Wed Dec 18 14:16:28 2002
@@ -125,17 +125,9 @@
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
-#define FTDI_SIO_BASE_BAUD_TO_DIVISOR(base, baud) ( \
-((base/2/baud) >> 3) | \
-(((base/2/baud) & 2) ? 0x8000 : 0) | \
-(((base/2/baud) & 4) ? 0x4000 : 0) | \
-((((base/2/baud) & 0x7) == 1) ? 0xc000 : 0) )
-
-#define FTDI_SIO_BAUD_TO_DIVISOR(baud) FTDI_SIO_BASE_BAUD_TO_DIVISOR(48000000, baud)
-
 /*
- * The ftdi_8U232AM_xxMHz_byyy constans have been removed. Their values can
- * be calculated as follows: FTDI_SIO_BAUD_TO_DIVISOR(xx000000, yyy)
+ * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
+ * are calculated internally.
  */
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
diff -urN linux-2.4.21-pre1/drivers/usb/serial/kobil_sct.c linux-2.4.21-pre2/drivers/usb/serial/kobil_sct.c
--- linux-2.4.21-pre1/drivers/usb/serial/kobil_sct.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/usb/serial/kobil_sct.c	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,713 @@
+/*
+ *  KOBIL USB Smart Card Terminal Driver
+ *
+ *  Copyright (C) 2002  KOBIL Systems GmbH 
+ *  Author: Thomas Wahrenbruch
+ *
+ *  Contact: linuxusb@kobil.de
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ *  patience.
+ *
+ * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
+ * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
+ * 
+ * TODO: High baudrates
+ *
+ * (12/03/2002) tw
+ *      Fixed bug with Pro-readers and PNP
+ *
+ * (11/13/2002) tw
+ *      Initial version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#include <linux/ioctl.h>
+
+
+#include "kobil_sct.h"
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/* Version Information */
+#define DRIVER_VERSION "12/03/2002"
+#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
+#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
+
+#define KOBIL_VENDOR_ID	           0x0D46
+#define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011
+#define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012
+#define KOBIL_USBTWIN_PRODUCT_ID   0x0078
+
+#define KOBIL_TIMEOUT    500
+#define KOBIL_BUF_LENGTH 300
+
+
+/* Function prototypes */
+static int  kobil_startup (struct usb_serial *serial);
+static void kobil_shutdown (struct usb_serial *serial);
+static int  kobil_open (struct usb_serial_port *port, struct file *filp);
+static void kobil_close (struct usb_serial_port *port, struct file *filp);
+static int  kobil_write (struct usb_serial_port *port, int from_user, 
+			 const unsigned char *buf, int count);
+static int  kobil_write_room(struct usb_serial_port *port);
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg);
+static void kobil_read_int_callback( struct urb *urb );
+static void kobil_write_callback( struct urb *purb );
+
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
+	{ }			/* Terminating entry */
+};
+
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type kobil_device = {
+	.owner =                THIS_MODULE,
+	.name =			"KOBIL USB smart card terminal",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		0,
+	.num_bulk_out =		0,
+	.num_ports =		1,
+	.startup =		kobil_startup,
+	.shutdown =		kobil_shutdown,
+	.ioctl =		kobil_ioctl,
+	.open =			kobil_open,
+	.close =		kobil_close,
+	.write =		kobil_write,
+	.write_room =           kobil_write_room,
+	.read_int_callback =	kobil_read_int_callback,
+};
+
+
+struct kobil_private {
+	int write_int_endpoint_address;
+	int read_int_endpoint_address;
+	unsigned char buf[KOBIL_BUF_LENGTH]; // buffer for the APDU to send
+	int filled;  // index of the last char in buf
+	int cur_pos; // index of the next char to send in buf
+	__u16 device_type;
+	int line_state;
+	struct termios internal_termios;
+};
+
+
+static int kobil_startup (struct usb_serial *serial)
+{
+	int i;
+	struct kobil_private *priv;
+	struct usb_device *pdev;
+	struct usb_config_descriptor *actconfig;
+	struct usb_interface *interface;
+	struct usb_interface_descriptor *altsetting;
+	struct usb_endpoint_descriptor *endpoint;
+
+	serial->port->private = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
+	if (!serial->port->private){
+		return -1;
+	}
+ 
+	priv = (struct kobil_private *) serial->port->private;
+	priv->filled = 0;
+	priv->cur_pos = 0;
+	priv->device_type = serial->product;
+	priv->line_state = 0;
+	
+	switch (priv->device_type){
+	case KOBIL_ADAPTER_B_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");
+		break;
+	case KOBIL_ADAPTER_K_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
+		break;
+	case KOBIL_USBTWIN_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL USBTWIN detected\n");
+		break;
+	}
+
+	// search for the neccessary endpoints
+	pdev = serial->dev;
+ 	actconfig = pdev->actconfig;
+ 	interface = actconfig->interface;
+	altsetting = interface->altsetting;
+ 	endpoint = altsetting->endpoint;
+  
+ 	for (i = 0; i < altsetting->bNumEndpoints; i++) {
+		endpoint = &altsetting->endpoint[i];
+		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->write_int_endpoint_address = endpoint->bEndpointAddress;
+ 		}
+ 		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt in  endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->read_int_endpoint_address = endpoint->bEndpointAddress;
+	 	}
+	}
+	return 0;
+}
+
+
+static void kobil_shutdown (struct usb_serial *serial)
+{
+	int i;
+  	dbg("%s - port %d", __FUNCTION__, serial->port->number);
+
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			kobil_close (&serial->port[i], NULL);
+		}
+		if (serial->port[i].private) {
+			kfree(serial->port[i].private);
+		}
+	} 
+}
+
+
+static int kobil_open (struct usb_serial_port *port, struct file *filp)
+{
+	int i, result = 0;
+	struct kobil_private *priv;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int write_urb_transfer_buffer_length = 8;
+	
+  	dbg("%s - port %d", __FUNCTION__, port->number);
+	priv = (struct kobil_private *) port->private;
+	priv->line_state = 0;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	// someone sets the dev to 0 if the close method has been called
+	port->interrupt_in_urb->dev = port->serial->dev;
+
+	
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through, otherwise it is scheduled, and with high
+	 * data rates (like with OHCI) data can get lost.
+	 */
+	port->tty->low_latency = 1;
+
+	// without this, every push_tty_char is echoed :-(  
+	port->tty->termios->c_lflag = 0;
+	port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
+	
+	// set up internal termios structure 
+	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
+	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
+	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
+	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
+	
+	for (i=0; i<NCCS; i++) {
+		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
+	}
+	
+	// allocate memory for transfer buffer
+	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+	if (! transfer_buffer) {
+		return -1;
+	} else {
+		memset(transfer_buffer, 0, transfer_buffer_length);
+	}
+	
+	// allocate write_urb
+	if (!port->write_urb) { 
+		dbg("%s - port %d  Allocating port->write_urb", __FUNCTION__, port->number);
+		port->write_urb = usb_alloc_urb(0);  
+		if (!port->write_urb) {
+			dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
+			return -1;
+		}
+	}
+ 
+	// allocate memory for write_urb transfer buffer
+	port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
+	if (! port->write_urb->transfer_buffer) {
+		return -1;
+	} 
+
+	// get hardware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetHWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+	
+	// get firmware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetFWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+
+	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
+		// Setting Baudrate, Parity and Stopbits
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		
+		// reset all queues
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+		// start reading (Adapter B 'cause PNP string)
+		result = usb_submit_urb( port->interrupt_in_urb ); 
+		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	kfree(transfer_buffer);
+	return 0;
+}
+
+
+static void kobil_close (struct usb_serial_port *port, struct file *filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb){
+		usb_unlink_urb( port->write_urb );
+		usb_free_urb( port->write_urb );
+		port->write_urb = 0;
+	}
+	if (port->interrupt_in_urb){
+		usb_unlink_urb (port->interrupt_in_urb);
+	}
+}
+
+
+static void kobil_read_int_callback( struct urb *purb )
+{  
+	int i;
+	struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
+	struct tty_struct *tty;
+	unsigned char *data = purb->transfer_buffer;
+	char *dbg_data;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (purb->status) {
+		dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);
+		return;
+	}
+	
+	tty = port->tty; 
+	if (purb->actual_length) {
+		
+		// BEGIN DEBUG
+		dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);  
+		if (! dbg_data) {
+			return;
+		}
+		memset(dbg_data, 0, (3 *  purb->actual_length + 10));
+		for (i = 0; i < purb->actual_length; i++) { 
+			sprintf(dbg_data +3*i, "%02X ", data[i]); 
+		}
+		dbg(" <-- %s", dbg_data );
+		kfree(dbg_data);
+		// END DEBUG
+
+		for (i = 0; i < purb->actual_length; ++i) {
+			// if we insert more than TTY_FLIPBUF_SIZE characters, we drop them.
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			// this doesn't actually push the data through unless tty->low_latency is set
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+	}
+}
+
+
+static void kobil_write_callback( struct urb *purb )
+{
+}
+
+
+static int kobil_write (struct usb_serial_port *port, int from_user, 
+			const unsigned char *buf, int count)
+{
+	int length = 0;
+	int result = 0;
+	int todo = 0;
+	struct kobil_private * priv;
+	int i;
+	char *data;
+
+	if (count == 0) {
+		dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
+		return 0;
+	}
+
+	priv = (struct kobil_private *) port->private;
+
+	if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
+		dbg("%s - port %d Error: write request bigger than buffer size", __FUNCTION__, port->number);
+		return -ENOMEM;
+	}
+	
+	// BEGIN DEBUG
+	data = (unsigned char *) kmalloc((3 * count + 10) * sizeof(char), GFP_KERNEL);  
+	if (! data) {
+		return (-1);
+	}
+	memset(data, 0, (3 * count + 10));
+	for (i = 0; i < count; i++) { 
+		sprintf(data +3*i, "%02X ", buf[i]); 
+	} 
+	dbg(" %d --> %s", port->number, data );
+	kfree(data);
+	// END DEBUG
+
+	// Copy data to buffer
+	if (from_user) {
+		if (copy_from_user(priv->buf + priv->filled, buf, count)) {
+			return -EFAULT;
+		}
+	} else {
+		memcpy (priv->buf + priv->filled, buf, count);
+	}
+
+	priv->filled = priv->filled + count;
+  
+
+	// only send complete block. TWIN and adapter K use the same protocol.
+	if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
+	     ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
+		
+		// stop reading (except TWIN)
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			usb_unlink_urb( port->interrupt_in_urb );
+		}
+		
+		todo = priv->filled - priv->cur_pos;
+
+		while(todo > 0) {
+			// max 8 byte in one urb (endpoint size)
+			length = (todo < 8) ? todo : 8;
+			// copy data to transfer buffer
+			memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
+			
+			usb_fill_bulk_urb( port->write_urb,
+					   port->serial->dev,
+					   usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address),
+					   port->write_urb->transfer_buffer,
+					   length,
+					   kobil_write_callback,
+					   port
+				);
+
+			priv->cur_pos = priv->cur_pos + length;
+			result = usb_submit_urb( port->write_urb );
+			dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
+			todo = priv->filled - priv->cur_pos;
+
+			if (todo > 0) {
+				//mdelay(16);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout(24 * HZ / 1000);
+			}
+
+		} // end while
+		
+		priv->filled = 0;
+		priv->cur_pos = 0;
+				
+		// start reading (except TWIN)	
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			// someone sets the dev to 0 if the close method has been called
+			port->interrupt_in_urb->dev = port->serial->dev;
+		
+			// start reading
+			result = usb_submit_urb( port->interrupt_in_urb ); 
+			dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+		}
+		
+	}
+	return count;  
+}
+
+
+static int kobil_write_room (struct usb_serial_port *port)
+{
+	return 8;
+}
+
+
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv;
+	int mask;
+	int result;
+	unsigned short urb_val = 0;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	char *settings;
+
+	priv = (struct kobil_private *) port->private;
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) {
+		// This device doesn't support ioctl calls
+		return 0;
+	}
+
+	switch (cmd) {
+	case TCGETS:   // 0x5401
+		result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return(result);
+		}
+		kernel_termios_to_user_termios((struct termios *)arg, &priv->internal_termios);
+		return 0;
+
+	case TCSETS:   // 0x5402
+		if (! &port->tty->termios) {
+			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
+			return -ENOTTY;
+		}
+		result = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return result;
+		}
+		user_termios_to_kernel_termios( &priv->internal_termios, (struct termios *)arg);
+		
+		settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+		if (! settings) {
+			return -ENOBUFS;
+		}
+		memset(settings, 0, 50);
+
+		switch (priv->internal_termios.c_cflag & CBAUD) {
+		case B1200:
+			urb_val = SUSBCR_SBR_1200;
+			strcat(settings, "1200 ");
+			break;
+		case B9600:
+		default:
+			urb_val = SUSBCR_SBR_9600;
+			strcat(settings, "9600 ");
+			break;
+		}
+
+		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+		
+		if (priv->internal_termios.c_cflag & PARENB) {
+			if  (priv->internal_termios.c_cflag & PARODD) {
+				urb_val |= SUSBCR_SPASB_OddParity;
+				strcat(settings, "Odd Parity");
+			} else {
+				urb_val |= SUSBCR_SPASB_EvenParity;
+				strcat(settings, "Even Parity");
+			}
+		} else {
+			urb_val |= SUSBCR_SPASB_NoParity;
+			strcat(settings, "No Parity");
+		}
+		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  urb_val,
+					  0,
+					  settings,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		kfree(settings);
+		return 0;
+    
+	case TCFLSH:   // 0x540B
+		result = usb_control_msg( port->serial->dev, 
+		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  NULL,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+
+	case TIOCMGET: // 0x5415
+		// allocate memory for transfer buffer
+		transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+		if (! transfer_buffer) {
+			return -ENOBUFS;
+		} else {
+			memset(transfer_buffer, 0, transfer_buffer_length);
+		}
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_GetStatusLineState,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+					  0,
+					  0,
+					  transfer_buffer,
+					  transfer_buffer_length,
+					  KOBIL_TIMEOUT
+			);
+	
+		dbg("%s - port %d Send get_status_line_state (TIOCMGET) URB returns: %i. Statusline: %02x", 
+		    __FUNCTION__, port->number, result, transfer_buffer[0]);
+	
+		if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) {
+			priv->line_state |= TIOCM_DSR;
+		} else {
+			priv->line_state &= ~TIOCM_DSR; 
+		}
+		
+		kfree(transfer_buffer);
+		return put_user(priv->line_state, (unsigned long *) arg);
+		
+	case TIOCMSET: // 0x5418
+		if (get_user(mask, (unsigned long *) arg)){
+			return -EFAULT;
+		}
+		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+			if ((mask & TIOCM_DTR) != 0){
+				dbg("%s - port %d Setting DTR", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing DTR", __FUNCTION__, port->number);
+			} 
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  ( ((mask & TIOCM_DTR) != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+			
+		} else {
+			if ((mask & TIOCM_RTS) != 0){
+				dbg("%s - port %d Setting RTS", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing RTS", __FUNCTION__, port->number);
+			}
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  (((mask & TIOCM_RTS) != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+		}
+		dbg("%s - port %d Send set_status_line (TIOCMSET) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+	}
+	return 0;
+}
+
+
+static int __init kobil_init (void)
+{
+	usb_serial_register (&kobil_device);
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return 0;
+}
+
+
+static void __exit kobil_exit (void)
+{
+	usb_serial_deregister (&kobil_device);
+}
+
+module_init(kobil_init);
+module_exit(kobil_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( "GPL" );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff -urN linux-2.4.21-pre1/drivers/usb/serial/kobil_sct.h linux-2.4.21-pre2/drivers/usb/serial/kobil_sct.h
--- linux-2.4.21-pre1/drivers/usb/serial/kobil_sct.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/drivers/usb/serial/kobil_sct.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,60 @@
+#define SUSBCRequest_SetBaudRateParityAndStopBits       1
+#define SUSBCR_SBR_MASK				0xFF00
+#define SUSBCR_SBR_1200				0x0100
+#define SUSBCR_SBR_9600				0x0200
+#define SUSBCR_SBR_19200			0x0400
+#define SUSBCR_SBR_28800			0x0800
+#define SUSBCR_SBR_38400			0x1000
+#define SUSBCR_SBR_57600			0x2000
+#define SUSBCR_SBR_115200			0x4000
+
+#define SUSBCR_SPASB_MASK			0x0070
+#define SUSBCR_SPASB_NoParity			0x0010
+#define SUSBCR_SPASB_OddParity			0x0020
+#define SUSBCR_SPASB_EvenParity			0x0040
+
+#define SUSBCR_SPASB_STPMASK			0x0003
+#define SUSBCR_SPASB_1StopBit			0x0001
+#define SUSBCR_SPASB_2StopBits			0x0002
+
+#define SUSBCRequest_SetStatusLinesOrQueues	2
+#define SUSBCR_SSL_SETRTS			0x0001
+#define SUSBCR_SSL_CLRRTS			0x0002
+#define SUSBCR_SSL_SETDTR			0x0004
+#define SUSBCR_SSL_CLRDTR			0x0010
+
+#define SUSBCR_SSL_PURGE_TXABORT		0x0100  // Kill the pending/current writes to the comm port.
+#define SUSBCR_SSL_PURGE_RXABORT		0x0200  // Kill the pending/current reads to the comm port.
+#define SUSBCR_SSL_PURGE_TXCLEAR		0x0400  // Kill the transmit queue if there.
+#define SUSBCR_SSL_PURGE_RXCLEAR		0x0800  // Kill the typeahead buffer if there.
+
+#define SUSBCRequest_GetStatusLineState		4
+#define SUSBCR_GSL_RXCHAR			0x0001  // Any Character received
+#define SUSBCR_GSL_TXEMPTY			0x0004  // Transmitt Queue Empty
+#define SUSBCR_GSL_CTS				0x0008  // CTS changed state
+#define SUSBCR_GSL_DSR				0x0010  // DSR changed state
+#define SUSBCR_GSL_RLSD				0x0020  // RLSD changed state
+#define SUSBCR_GSL_BREAK			0x0040  // BREAK received
+#define SUSBCR_GSL_ERR				0x0080  // Line status error occurred
+#define SUSBCR_GSL_RING				0x0100  // Ring signal detected
+
+#define SUSBCRequest_Misc			8
+#define SUSBCR_MSC_ResetReader			0x0001	// use a predefined reset sequence
+#define SUSBCR_MSC_ResetAllQueues	        0x0002	// use a predefined sequence to reset the internal queues
+
+#define SUSBCRequest_GetMisc			0x10
+#define SUSBCR_MSC_GetFWVersion			0x0001	/* get the firmware version from device,
+							   coded like this 0xHHLLBBPP
+							   with HH = Firmware Version High Byte
+							   LL = Firmware Version Low Byte
+							   BB = Build Number
+							   PP = Further Attributes
+							*/
+
+#define SUSBCR_MSC_GetHWVersion			0x0002	/* get the hardware version from device
+							   coded like this 0xHHLLPPRR
+							   with HH = Software Version High Byte
+							   LL = Software Version Low Byte
+							   PP = Further Attributes
+							   RR = Reserved for the hardware ID 
+							*/
diff -urN linux-2.4.21-pre1/drivers/usb/storage/unusual_devs.h linux-2.4.21-pre2/drivers/usb/storage/unusual_devs.h
--- linux-2.4.21-pre1/drivers/usb/storage/unusual_devs.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/usb/storage/unusual_devs.h	Wed Dec 18 14:16:28 2002
@@ -207,9 +207,9 @@
 		US_FL_FIX_INQUIRY | US_FL_START_STOP ),
 
 /* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0422, 
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0440, 
 		"Sony",
-		"DSC-S30/S70/S75/505V/F505/F707", 
+		"DSC-S30/S70/S75/505V/F505/F707/F717", 
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
 
@@ -487,6 +487,18 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
+ * Only revision 1.13 tested (same for all of the above devices,
+ * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
  * to the USB storage specification in two ways:
  * - They tell us they are using transport protocol CBI. In reality they
diff -urN linux-2.4.21-pre1/drivers/usb/uhci.c linux-2.4.21-pre2/drivers/usb/uhci.c
--- linux-2.4.21-pre1/drivers/usb/uhci.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/usb/uhci.c	Wed Dec 18 14:16:28 2002
@@ -1498,7 +1498,6 @@
 
 	uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	INIT_LIST_HEAD(&urb->urb_list);
 	usb_inc_dev_use(urb->dev);
 
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
@@ -1515,6 +1514,7 @@
 		return ret;
 	}
 
+	INIT_LIST_HEAD(&urb->urb_list);
 	if (!uhci_alloc_urb_priv(uhci, urb)) {
 		ret = -ENOMEM;
 
diff -urN linux-2.4.21-pre1/drivers/usb/usb.c linux-2.4.21-pre2/drivers/usb/usb.c
--- linux-2.4.21-pre1/drivers/usb/usb.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/usb/usb.c	Wed Dec 18 14:16:28 2002
@@ -1785,17 +1785,17 @@
  * These are the actual routines to send
  * and receive control messages.
  */
-#ifdef CONFIG_USB_LONG_TIMEOUT
-#define GET_TIMEOUT 4
-#else
-#define GET_TIMEOUT 3
-#endif
-#define SET_TIMEOUT 3
+
+/* USB spec identifies 5 second timeouts.
+ * Some devices (MGE Ellipse UPSes, etc) need it, too.
+ */
+#define GET_TIMEOUT 5
+#define SET_TIMEOUT 5
 
 int usb_set_address(struct usb_device *dev)
 {
 	return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-		0, dev->devnum, 0, NULL, 0, HZ * GET_TIMEOUT);
+		0, dev->devnum, 0, NULL, 0, HZ * SET_TIMEOUT);
 }
 
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
diff -urN linux-2.4.21-pre1/drivers/usb/usbnet.c linux-2.4.21-pre2/drivers/usb/usbnet.c
--- linux-2.4.21-pre1/drivers/usb/usbnet.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/usb/usbnet.c	Wed Dec 18 14:16:28 2002
@@ -35,7 +35,7 @@
  *	- GeneSys GL620USB-A
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
  *	- Prolific PL-2301/2302 (replaces "plusb" driver)
- *	- SA-1100 (and similar) Linux PDAs like iPaq, Yopy, and Zaurus
+ *	- PXA-250 or SA-1100 Linux PDAs like iPaq, Yopy, and Zaurus
  *
  * USB devices can implement their side of this protocol at the cost
  * of two bulk endpoints; it's not restricted to "cable" applications.
@@ -63,8 +63,7 @@
  *
  * - SA-1100 PDAs ... the standard ARM Linux SA-1100 support works nicely,
  *   as found in www.handhelds.org and other kernels.  The Sharp/Lineo
- *   kernels use different drivers, which also work here, but they've made
- *   "uhci-hcd" (2.5) die.
+ *   kernels use different drivers, which also talk to this code.
  *
  * Interop with more Win32 drivers may be a good thing.
  *
@@ -118,7 +117,10 @@
  * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
  *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
  *		Use "locally assigned" IEEE802 address space. (Brad Hards)
- * 18-oct-2002  Support for Zaurus (Pavel Machek), related cleanup (db).
+ * 18-oct-2002	Support for Zaurus (Pavel Machek), related cleanup (db).
+ * 15-dec-2002	Partial sync with 2.5 code: cleanups and stubbed PXA-250
+ * 		support (db), fix for framing issues on Z, net1080, and
+ * 		gl620a (Toby Milne)
  *
  *-------------------------------------------------------------------------*/
 
@@ -160,7 +162,7 @@
 #define	CONFIG_USB_GENESYS
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
-#define	CONFIG_USB_SA1110
+#define	CONFIG_USB_SA1100
 #define	CONFIG_USB_ZAURUS
 
 
@@ -172,6 +174,8 @@
  * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
  * Several dozen bytes of IPv4 data can fit in two such transactions.
  * One maximum size Ethernet packet takes twenty four of them.
+ * For high speed, each frame comfortably fits almost 36 max size
+ * Ethernet packets (so queues should be bigger).
  */
 #ifdef REALLY_QUEUE
 #define	RX_QLEN		4
@@ -243,6 +247,7 @@
 	int		flags;
 #define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */ 
 #define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
+#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
 #define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 
 	/* reset device ... can sleep */
@@ -553,7 +558,7 @@
 	}
 
 	// fill irq urb
-	FILL_INT_URB (priv->irq_urb, dev->udev,
+	usb_fill_int_urb (priv->irq_urb, dev->udev,
 		usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE),
 		priv->irq_buf, INTERRUPT_BUFSIZE,
 		gl_interrupt_complete, 0,
@@ -1245,13 +1250,34 @@
 
 
 
+#ifdef	CONFIG_USB_PXA
+
+/*-------------------------------------------------------------------------
+ *
+ * PXA250 and PXA210 use XScale cores (ARM v5TE) with better USB support,
+ * and different USB endpoint numbering than the SA1100 devices.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	pxa_info = {
+	.description =	"PXA-250 Linux Device",
+	.check_connect = always_connected,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_PXA */
+
+
+
 #ifdef	CONFIG_USB_SA1100
 
 /*-------------------------------------------------------------------------
  *
  * Intel's SA-1100 chip integrates basic USB support, and is used
  * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
- * When they run Linux, arch/arm/sa1100/usb-eth.c may be used to
+ * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
  * network using minimal USB framing data.
  *
  * This describes the driver currently in standard ARM Linux kernels.
@@ -1283,16 +1309,17 @@
 /*-------------------------------------------------------------------------
  *
  * Zaurus is also a SA-1110 based PDA, but one using a different driver
- * for its USB slave/target controller than the case above.
+ * (and framing) for its USB slave/gadget controller than the case above.
  *
- * The key differences are that (a) it's got a msft-friendly configuration,
- * and (b) the linux-friendly framing adds a crc32 to cope with some
- * memory corruption observed with usb-to-memory DMA in some cases.
- * (SA-1100 has a lot of nasty USB errata that need working around.)
+ * For the current version of that driver, the main way that framing is
+ * nonstandard (also from perspective of the CDC ethernet model!) is a
+ * crc32, added to help detect when some sa1100 usb-to-memory DMA errata
+ * haven't been fully worked around.
  *
  *-------------------------------------------------------------------------*/
 
-// FIXME try <linux/crc32.h> instead
+// NOTE: so far on 2.4 <linux/crc32.h> isn't for "bulk data" like this.
+// On 2.5 crc32_le() handles this for us.
 
 static const u32 crc32_table [256] = {
     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
@@ -1373,22 +1400,25 @@
 
 static const struct driver_info	zaurus_sl5x00_info = {
 	.description =	"Sharp Zaurus SL-5x00",
+	.flags =	FLAG_FRAMING_Z,
 	.check_connect = always_connected,
 	.tx_fixup = 	zaurus_tx_fixup,
 
-	// SA-1100 fixed function endpoints
 	.in = 2, .out = 1,
 	.epsize = 64,
 };
 static const struct driver_info	zaurus_sla300_info = {
 	.description =	"Sharp Zaurus SL-A300",
+	.flags =	FLAG_FRAMING_Z,
 	.check_connect = always_connected,
 	.tx_fixup = 	zaurus_tx_fixup,
 
-	// two of the many PXA-250 fixed function endpoints
 	.in = 1, .out = 2,
 	.epsize = 64,
 };
+
+// SL-5600 and C-700 are PXA based; should resemble A300
+
 #endif
 
 
@@ -1431,7 +1461,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* urb completions are currently in_irq; avoid doing real work then. */
+/* urb completions may be in_irq; avoid doing real work then. */
 
 static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
 {
@@ -1485,6 +1515,11 @@
 		size = GL_RCV_BUF_SIZE;
 	else
 #endif
+#ifdef CONFIG_USB_ZAURUS
+	if (dev->driver_info->flags & FLAG_FRAMING_Z)
+		size = 6 + (sizeof (struct ethhdr) + dev->net.mtu);
+	else
+#endif
 		size = (sizeof (struct ethhdr) + dev->net.mtu);
 
 	if ((skb = alloc_skb (size, flags)) == 0) {
@@ -1500,15 +1535,10 @@
 	entry->state = rx_start;
 	entry->length = 0;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#if 0
-	// Idle-but-posted reads with UHCI really chew up
-	// PCI bandwidth unless FSBR is disabled
-	urb->transfer_flags |= USB_NO_FSBR;
-#endif
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -1552,8 +1582,6 @@
 	if (skb->len) {
 		int	status;
 
-// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
-
 		skb->dev = &dev->net;
 		skb->protocol = eth_type_trans (skb, &dev->net);
 		dev->stats.rx_packets++;
@@ -1932,7 +1960,7 @@
 static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
 	struct usbnet		*dev = (struct usbnet *) net->priv;
-	int			length = skb->len;
+	int			length;
 	int			retval = NET_XMIT_SUCCESS;
 	struct urb		*urb = 0;
 	struct skb_data		*entry;
@@ -1952,6 +1980,7 @@
 			goto drop;
 		}
 	}
+	length = skb->len;
 
 	if (!(urb = ALLOC_URB (0, GFP_ATOMIC))) {
 		dbg ("no urb");
@@ -1966,6 +1995,7 @@
 
 	// FIXME: reorganize a bit, so that fixup() fills out NetChip
 	// framing too. (Packet ID update needs the spinlock...)
+	// [ BETTER:  we already own net->xmit_lock, that's enough ]
 
 #ifdef	CONFIG_USB_NET1080
 	if (info->flags & FLAG_FRAMING_NC) {
@@ -1982,11 +2012,10 @@
 	if ((length % EP_SIZE (dev)) == 0)
 		skb->len++;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
 
@@ -2302,6 +2331,18 @@
 },
 #endif
 
+#ifdef	CONFIG_USB_PXA
+/*
+ * PXA250 or PXA210 ...  these use a "usb-eth" driver much like
+ * the sa1100 one.
+ */
+{
+	// Compaq "Itsy" vendor/product id, version "2.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0x0200, 0x0200),
+	.driver_info =	(unsigned long) &pxa_info,
+}, 
+#endif
+
 #ifdef	CONFIG_USB_SA1100
 /*
  * SA-1100 using standard ARM Linux kernels, or compatible.
@@ -2310,7 +2351,8 @@
  */
 {
 	// 1183 = 0x049F, both used as hex values?
-	USB_DEVICE (0x049F, 0x505A),	// iPaq: Compaq "Itsy"
+	// Compaq "Itsy" vendor/product id, version "0.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0, 0),
 	.driver_info =	(unsigned long) &linuxdev_info,
 }, {
 	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
@@ -2345,8 +2387,6 @@
 },
 #endif
 
-/* KC2190 from www.sepoong.co.kr "InstaNET" */
-
 	{ },		// END
 };
 MODULE_DEVICE_TABLE (usb, products);
diff -urN linux-2.4.21-pre1/drivers/video/clgenfb.c linux-2.4.21-pre2/drivers/video/clgenfb.c
--- linux-2.4.21-pre1/drivers/video/clgenfb.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/video/clgenfb.c	Wed Dec 18 14:16:28 2002
@@ -15,6 +15,9 @@
  *	Lars Hecking:
  *	Amiga updates and testing.
  *
+ *	Cliff Matthews <ctm@ardi.com>:
+ *	16bpp fix for CL-GD7548 (uses info from XFree86 4.2.0 source)
+ *
  * Original clgenfb author:  Frank Neumann
  *
  * Based on retz3fb.c and clgen.c:
@@ -403,6 +406,9 @@
 
 #ifdef CONFIG_PCI
 	struct pci_dev *pdev;
+#define IS_7548(x) ((x)->pdev->device == PCI_DEVICE_ID_CIRRUS_7548)
+#else
+#define IS_7548(x) (FALSE)
 #endif
 };
 
@@ -970,7 +976,10 @@
 
 	DPRINTK ("desired pixclock: %ld kHz\n", freq);
 
-	maxclock = clgen_board_info[fb_info->btype].maxclock;
+	if (IS_7548(fb_info))
+		maxclock = 80100;
+	else
+		maxclock = clgen_board_info[fb_info->btype].maxclock;
 	_par->multiplexing = 0;
 
 	/* If the frequency is greater than we can support, we might be able
@@ -1478,10 +1487,17 @@
 
 		case BT_ALPINE:
 			DPRINTK (" (for GD543x)\n");
-			if (_par->HorizRes >= 1024)
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
-			else
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			if (IS_7548(fb_info)) {
+				vga_wseq (fb_info->regs, CL_SEQR7, 
+					  (vga_rseq (fb_info->regs, CL_SEQR7) & 0xE0)
+					  | 0x17);
+				WHDR (fb_info, 0xC1);
+			} else {
+				if (_par->HorizRes >= 1024)
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
+				else
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			}	
 			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
 			break;
 
@@ -1594,6 +1610,11 @@
 			_par->var.bits_per_pixel);
 	}
 
+	if (IS_7548(fb_info)) {
+		vga_wseq (fb_info->regs, CL_SEQR2D, 
+			vga_rseq (fb_info->regs, CL_SEQR2D) | 0xC0);
+	}
+
 	vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
 	tmp = 0x22;
 	if (offset & 0x100)
diff -urN linux-2.4.21-pre1/drivers/video/clgenfb.h linux-2.4.21-pre2/drivers/video/clgenfb.h
--- linux-2.4.21-pre1/drivers/video/clgenfb.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/drivers/video/clgenfb.h	Wed Dec 18 14:16:28 2002
@@ -60,6 +60,7 @@
 #define CL_SEQR1D	0x1d	/* VCLK2 Denominator and Post-Scalar Value */
 #define CL_SEQR1E	0x1e	/* VCLK3 Denominator and Post-Scalar Value */
 #define CL_SEQR1F	0x1f	/* BIOS ROM write enable and MCLK Select */
+#define CL_SEQR2D	0x2d	/* unknown, snagged from XFree86 4.2.0 */
 
 /*** CRT Controller Registers ***/
 #define CL_CRT22	0x22	/* Graphics Data Latches ReadBack */
diff -urN linux-2.4.21-pre1/drivers/video/fbmem.c linux-2.4.21-pre2/drivers/video/fbmem.c
--- linux-2.4.21-pre1/drivers/video/fbmem.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/video/fbmem.c	Wed Dec 18 14:16:28 2002
@@ -647,6 +647,8 @@
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
 #elif defined(__ia64__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 #elif defined(__hppa__)
diff -urN linux-2.4.21-pre1/drivers/video/sti/sticore.c linux-2.4.21-pre2/drivers/video/sti/sticore.c
--- linux-2.4.21-pre1/drivers/video/sti/sticore.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/video/sti/sticore.c	Wed Dec 18 14:16:28 2002
@@ -467,6 +467,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_FB
 struct sti_cooked_font * __init
 sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
 {
@@ -523,6 +524,13 @@
 
 	return cooked_font;
 }
+#else
+struct sti_cooked_font * __init
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
+{
+	return NULL;
+}
+#endif
 
 struct sti_cooked_font * __init
 sti_select_font(struct sti_cooked_rom *rom,
diff -urN linux-2.4.21-pre1/drivers/video/sti/stifb.c linux-2.4.21-pre2/drivers/video/sti/stifb.c
--- linux-2.4.21-pre1/drivers/video/sti/stifb.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/drivers/video/sti/stifb.c	Wed Dec 18 14:16:28 2002
@@ -133,7 +133,7 @@
 #endif			
 };
 
-static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
+static int stifb_force_bpp[MAX_STI_ROMS];
 
 /* ------------------- chipset specific functions -------------------------- */
 
@@ -1290,7 +1290,10 @@
 		fb->id = S9000_ID_A1659A;
 		break;
 	case S9000_ID_A1439A:	/* CRX24/A1439A */
-		bpp = 32;
+		if (force_bpp == 8 || force_bpp == 32)
+		  bpp = force_bpp;
+		else
+		  bpp = 32;
 		break;
 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
diff -urN linux-2.4.21-pre1/fs/buffer.c linux-2.4.21-pre2/fs/buffer.c
--- linux-2.4.21-pre1/fs/buffer.c	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/fs/buffer.c	Wed Dec 18 14:16:28 2002
@@ -327,9 +327,9 @@
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
+	unlock_super(sb);
 	if (sb->s_op && sb->s_op->sync_fs)
 		sb->s_op->sync_fs(sb);
-	unlock_super(sb);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -689,13 +689,13 @@
 			/* All buffers in the lru lists are mapped */
 			if (!buffer_mapped(bh))
 				BUG();
-			if (buffer_dirty(bh))
+			if (buffer_dirty(bh) && destroy_dirty_buffers)
 				printk("invalidate: dirty buffer\n");
 			if (!atomic_read(&bh->b_count)) {
 				if (destroy_dirty_buffers || !buffer_dirty(bh)) {
 					remove_inode_queue(bh);
 				}
-			} else
+			} else if (!bdev->bd_openers)
 				printk("invalidate: busy buffer\n");
 
 			write_unlock(&hash_table_lock);
diff -urN linux-2.4.21-pre1/fs/ext3/inode.c linux-2.4.21-pre2/fs/ext3/inode.c
--- linux-2.4.21-pre1/fs/ext3/inode.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/ext3/inode.c	Wed Dec 18 14:16:28 2002
@@ -2270,7 +2270,7 @@
 			}
 		}
 	}
-	raw_inode->i_generation = le32_to_cpu(inode->i_generation);
+	raw_inode->i_generation = cpu_to_le32(inode->i_generation);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_block[0] =
 			cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
diff -urN linux-2.4.21-pre1/fs/ext3/namei.c linux-2.4.21-pre2/fs/ext3/namei.c
--- linux-2.4.21-pre1/fs/ext3/namei.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/ext3/namei.c	Wed Dec 18 14:16:28 2002
@@ -429,8 +429,11 @@
 {
 	int err = ext3_add_entry(handle, dentry, inode);
 	if (!err) {
-		d_instantiate(dentry, inode);
-		return 0;
+		err = ext3_mark_inode_dirty(handle, inode);
+		if (err == 0) {
+			d_instantiate(dentry, inode);
+			return 0;
+		}
 	}
 	ext3_dec_count(handle, inode);
 	iput(inode);
@@ -465,7 +468,6 @@
 		inode->i_fop = &ext3_file_operations;
 		inode->i_mapping->a_ops = &ext3_aops;
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -490,7 +492,6 @@
 	if (!IS_ERR(inode)) {
 		init_special_inode(inode, mode, rdev);
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -934,7 +935,6 @@
 	}
 	inode->u.ext3_i.i_disksize = inode->i_size;
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 out_stop:
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -971,7 +971,6 @@
 	atomic_inc(&inode->i_count);
 
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 	ext3_journal_stop(handle, dir);
 	return err;
 }
diff -urN linux-2.4.21-pre1/fs/lockd/svc.c linux-2.4.21-pre2/fs/lockd/svc.c
--- linux-2.4.21-pre1/fs/lockd/svc.c	Sun Oct 21 10:32:33 2001
+++ linux-2.4.21-pre2/fs/lockd/svc.c	Wed Dec 18 14:16:28 2002
@@ -72,11 +72,6 @@
 	return grace_period + jiffies;
 }
 
-static inline void clear_grace_period(void)
-{
-	nlmsvc_grace_period = 0;
-}
-
 /*
  * This is the lockd kernel thread
  */
@@ -142,10 +137,8 @@
 		 * (Theoretically, there shouldn't even be blocked locks
 		 * during grace period).
 		 */
-		if (!nlmsvc_grace_period) {
+		if (!nlmsvc_grace_period)
 			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(grace_period_expire, jiffies))
-			clear_grace_period();
 
 		/*
 		 * Find a socket with data available and call its
@@ -175,6 +168,9 @@
 				nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
 		}
 
+		if (nlmsvc_grace_period &&
+		    time_before(grace_period_expire, jiffies))
+			nlmsvc_grace_period = 0;
 		svc_process(serv, rqstp);
 
 		/* Unlock export hash tables */
diff -urN linux-2.4.21-pre1/fs/nfs/file.c linux-2.4.21-pre2/fs/nfs/file.c
--- linux-2.4.21-pre1/fs/nfs/file.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.21-pre2/fs/nfs/file.c	Wed Dec 18 14:16:28 2002
@@ -187,6 +187,7 @@
 	if (!inode)
 		return 0;
 
+	NFS_SetPageSync(page);
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
diff -urN linux-2.4.21-pre1/fs/nfs/read.c linux-2.4.21-pre2/fs/nfs/read.c
--- linux-2.4.21-pre1/fs/nfs/read.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfs/read.c	Wed Dec 18 14:16:28 2002
@@ -171,11 +171,16 @@
 	struct nfs_page	*new;
 
 	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
-	if (IS_ERR(new))
+	if (IS_ERR(new)) {
+		SetPageError(page);
+		NFS_ClearPageSync(page);
+		UnlockPage(page);
 		return PTR_ERR(new);
+	}
 	nfs_mark_request_read(new);
 
-	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	if (NFS_TestClearPageSync(page) ||
+	    inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
 	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
 		nfs_pagein_inode(inode, 0, 0);
 	return 0;
@@ -222,6 +227,7 @@
 		req = nfs_list_entry(head->next);
 		page = req->wb_page;
 		nfs_list_remove_request(req);
+		NFS_ClearPageSync(page);
 		SetPageError(page);
 		UnlockPage(page);
 		nfs_clear_request(req);
@@ -429,6 +435,7 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
+		NFS_ClearPageSync(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
@@ -482,6 +489,7 @@
 	return error;
 
 out_error:
+	NFS_ClearPageSync(page);
 	UnlockPage(page);
 	goto out;
 }
diff -urN linux-2.4.21-pre1/fs/nfsd/nfs3proc.c linux-2.4.21-pre2/fs/nfsd/nfs3proc.c
--- linux-2.4.21-pre1/fs/nfsd/nfs3proc.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfsd/nfs3proc.c	Wed Dec 18 14:16:28 2002
@@ -672,7 +672,7 @@
   PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
   PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
   PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
   PROC(read,	 read,		read,		fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
   PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
   PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
diff -urN linux-2.4.21-pre1/fs/nfsd/nfsfh.c linux-2.4.21-pre2/fs/nfsd/nfsfh.c
--- linux-2.4.21-pre1/fs/nfsd/nfsfh.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfsd/nfsfh.c	Wed Dec 18 14:16:28 2002
@@ -620,6 +620,13 @@
 			switch (fh->fh_fileid_type) {
 			case 0:
 				dentry = dget(exp->ex_dentry);
+				/* need to revalidate the inode */
+				inode = dentry->d_inode;
+				if (inode->i_op && inode->i_op->revalidate)
+					if (inode->i_op->revalidate(dentry)) {
+						dput(dentry);
+						dentry = ERR_PTR(-ESTALE);
+					}
 				break;
 			default:
 				dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
@@ -671,11 +678,16 @@
 
 	/* Type can be negative to e.g. exclude directories from linking */
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
-		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		if (type == S_IFDIR)
+			error = nfserr_notdir;
+		else if ((inode->i_mode & S_IFMT) == S_IFDIR)
+			error = nfserr_isdir;
+		else
+			error = nfserr_inval;
 		goto out;
 	}
 	if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
-		error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		error = (type == -S_IFDIR)? nfserr_isdir : nfserr_notdir;
 		goto out;
 	}
 
diff -urN linux-2.4.21-pre1/fs/nfsd/nfsproc.c linux-2.4.21-pre2/fs/nfsd/nfsproc.c
--- linux-2.4.21-pre1/fs/nfsd/nfsproc.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfsd/nfsproc.c	Wed Dec 18 14:16:28 2002
@@ -545,7 +545,7 @@
   PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
   PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
diff -urN linux-2.4.21-pre1/fs/nfsd/nfsxdr.c linux-2.4.21-pre2/fs/nfsd/nfsxdr.c
--- linux-2.4.21-pre1/fs/nfsd/nfsxdr.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfsd/nfsxdr.c	Wed Dec 18 14:16:28 2002
@@ -385,7 +385,7 @@
 {
 	struct statfs	*stat = &resp->stats;
 
-	*p++ = htonl(8 * 1024);		/* max transfer size */
+	*p++ = htonl(NFSSVC_MAXBLKSIZE);	/* max transfer size */
 	*p++ = htonl(stat->f_bsize);
 	*p++ = htonl(stat->f_blocks);
 	*p++ = htonl(stat->f_bfree);
diff -urN linux-2.4.21-pre1/fs/nfsd/vfs.c linux-2.4.21-pre2/fs/nfsd/vfs.c
--- linux-2.4.21-pre1/fs/nfsd/vfs.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/nfsd/vfs.c	Wed Dec 18 14:16:28 2002
@@ -168,11 +168,13 @@
 			mntput(mnt);
 		}
 	}
-	/*
-	 * Note: we compose the file handle now, but as the
-	 * dentry may be negative, it may need to be updated.
-	 */
-	err = fh_compose(resfh, exp, dentry, fhp);
+
+	if (dentry->d_inode && dentry->d_inode->i_op &&
+	    dentry->d_inode->i_op->revalidate &&
+	    dentry->d_inode->i_op->revalidate(dentry))
+		err = nfserr_noent;
+	else
+		err = fh_compose(resfh, exp, dentry, fhp);
 	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
 out:
diff -urN linux-2.4.21-pre1/fs/read_write.c linux-2.4.21-pre2/fs/read_write.c
--- linux-2.4.21-pre1/fs/read_write.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/fs/read_write.c	Wed Dec 18 14:16:28 2002
@@ -218,7 +218,7 @@
 	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
 
-	ssize_t tot_len;
+	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
 	ssize_t ret, i;
@@ -259,12 +259,19 @@
 	tot_len = 0;
 	ret = -EINVAL;
 	for (i = 0 ; i < count ; i++) {
-		ssize_t tmp = tot_len;
 		ssize_t len = (ssize_t) iov[i].iov_len;
 		if (len < 0)	/* size_t not fitting an ssize_t .. */
 			goto out;
 		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the ssize_t */
+		/* We must do this work unsigned - signed overflow is
+		   undefined and gcc 3.2 now uses that fact sometimes... 
+		   
+		   FIXME: put in a proper limits.h for each platform */
+#if BITS_PER_LONG==64
+		if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
+#else
+		if (tot_len > 0x7FFFFFFFUL)
+#endif		
 			goto out;
 	}
 
diff -urN linux-2.4.21-pre1/fs/reiserfs/fix_node.c linux-2.4.21-pre2/fs/reiserfs/fix_node.c
--- linux-2.4.21-pre1/fs/reiserfs/fix_node.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/fs/reiserfs/fix_node.c	Wed Dec 18 14:16:28 2002
@@ -2059,7 +2059,7 @@
 	    /* getting memory with GFP_KERNEL priority may involve
                balancing now (due to indirect_to_direct conversion on
                dcache shrinking). So, release path and collected
-               resourses here */
+               resources here */
 	    free_buffers_in_tb (tb);
 	    buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb);
 	    if ( !buf ) {
diff -urN linux-2.4.21-pre1/fs/select.c linux-2.4.21-pre2/fs/select.c
--- linux-2.4.21-pre1/fs/select.c	Mon Sep 10 13:04:33 2001
+++ linux-2.4.21-pre2/fs/select.c	Wed Dec 18 14:16:28 2002
@@ -417,7 +417,7 @@
 	int nchunks, nleft;
 
 	/* Do a sanity check on nfds ... */
-	if (nfds > NR_OPEN)
+	if (nfds > current->files->max_fdset && nfds > OPEN_MAX)
 		return -EINVAL;
 
 	if (timeout) {
diff -urN linux-2.4.21-pre1/include/asm-alpha/ide.h linux-2.4.21-pre2/include/asm-alpha/ide.h
--- linux-2.4.21-pre1/include/asm-alpha/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-alpha/ide.h	Wed Dec 18 14:16:28 2002
@@ -80,6 +80,8 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMalpha_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-alpha/mmzone.h linux-2.4.21-pre2/include/asm-alpha/mmzone.h
--- linux-2.4.21-pre1/include/asm-alpha/mmzone.h	Thu May 24 15:20:18 2001
+++ linux-2.4.21-pre2/include/asm-alpha/mmzone.h	Wed Dec 18 14:16:28 2002
@@ -86,7 +86,7 @@
 
 /*
  * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
+ * and returns the mem_map of that node.
  */
 #define ADDR_TO_MAPBASE(kaddr) \
 			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
diff -urN linux-2.4.21-pre1/include/asm-arm/ide.h linux-2.4.21-pre2/include/asm-arm/ide.h
--- linux-2.4.21-pre1/include/asm-arm/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-arm/ide.h	Wed Dec 18 14:16:28 2002
@@ -26,6 +26,8 @@
 #define ide_default_io_base(i)		((ide_ioreg_t)0)
 #define ide_default_irq(b)		(0)
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMARM_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-arm/proc-armo/system.h linux-2.4.21-pre2/include/asm-arm/proc-armo/system.h
--- linux-2.4.21-pre1/include/asm-arm/proc-armo/system.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.21-pre2/include/asm-arm/proc-armo/system.h	Wed Dec 18 14:16:28 2002
@@ -127,4 +127,6 @@
 	  : "memory");					\
 	} while (0)
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #endif
diff -urN linux-2.4.21-pre1/include/asm-arm/proc-armv/system.h linux-2.4.21-pre2/include/asm-arm/proc-armv/system.h
--- linux-2.4.21-pre1/include/asm-arm/proc-armv/system.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.21-pre2/include/asm-arm/proc-armv/system.h	Wed Dec 18 14:16:28 2002
@@ -141,6 +141,8 @@
 	: "r" (x)						\
 	: "memory")
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
diff -urN linux-2.4.21-pre1/include/asm-cris/atomic.h linux-2.4.21-pre2/include/asm-cris/atomic.h
--- linux-2.4.21-pre1/include/asm-cris/atomic.h	Thu Jul 26 15:10:06 2001
+++ linux-2.4.21-pre2/include/asm-cris/atomic.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
+/* $Id: atomic.h,v 1.4 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef __ASM_CRIS_ATOMIC__
 #define __ASM_CRIS_ATOMIC__
@@ -27,7 +27,7 @@
 
 /* These should be written in asm but we do it in C for now. */
 
-static __inline__ void atomic_add(int i, volatile atomic_t *v)
+extern __inline__ void atomic_add(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -36,7 +36,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+extern __inline__ void atomic_sub(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -45,7 +45,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_add_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_add_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -56,7 +56,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -67,7 +67,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -78,7 +78,7 @@
 	return retval;
 }
 
-static __inline__ void atomic_inc(volatile atomic_t *v)
+extern __inline__ void atomic_inc(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -87,7 +87,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_dec(volatile atomic_t *v)
+extern __inline__ void atomic_dec(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -96,7 +96,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_inc_return(volatile atomic_t *v)
+extern __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -107,7 +107,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_dec_return(volatile atomic_t *v)
+extern __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -117,7 +117,7 @@
 	restore_flags(flags);
 	return retval;
 }
-static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -128,7 +128,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
diff -urN linux-2.4.21-pre1/include/asm-cris/bitops.h linux-2.4.21-pre2/include/asm-cris/bitops.h
--- linux-2.4.21-pre1/include/asm-cris/bitops.h	Mon Feb 25 11:38:10 2002
+++ linux-2.4.21-pre2/include/asm-cris/bitops.h	Wed Dec 18 14:16:28 2002
@@ -89,7 +89,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_set_bit(int nr, void *addr)
+extern __inline__ int test_and_set_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -120,7 +120,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_clear_bit(int nr, void *addr)
+extern __inline__ int test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -146,7 +146,7 @@
  * but actually fail.  You must protect multiple accesses with a lock.
  */
 
-static __inline__ int __test_and_clear_bit(int nr, void *addr)
+extern __inline__ int __test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -166,7 +166,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_change_bit(int nr, void *addr)
+extern __inline__ int test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -183,7 +183,7 @@
 
 /* WARNING: non atomic and it can be reordered! */
 
-static __inline__ int __test_and_change_bit(int nr, void *addr)
+extern __inline__ int __test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -204,7 +204,7 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int test_bit(int nr, const void *addr)
+extern __inline__ int test_bit(int nr, const void *addr)
 {
 	unsigned int mask;
 	unsigned int *adr = (unsigned int *)addr;
@@ -225,7 +225,7 @@
  * number.  They differ in that the first function also inverts all bits
  * in the input.
  */
-static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
 {
 	/* Let's just say we return the result in the same register as the
 	   input.  Saying we clobber the input but can return the result
@@ -241,7 +241,7 @@
 	return res;
 }
 
-static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapwbrlz(unsigned long w)
 {
 	unsigned res;
 	__asm__ ("swapwbr %0 \n\t"
@@ -255,7 +255,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long w)
+extern __inline__ unsigned long ffz(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -268,7 +268,7 @@
  * Somewhat like ffz but the equivalent of generic_ffs: in contrast to
  * ffz we return the first one-bit *plus one*.
  */
-static __inline__ unsigned long ffs(unsigned long w)
+extern __inline__ unsigned long kernel_ffs(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -277,13 +277,20 @@
 		: w ? cris_swapwbrlz (w) + 1 : 0;
 }
 
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which doesn't have the same semantics.  We don't want to
+ * use -fno-builtin, so just hide the name ffs.
+ */
+#define ffs kernel_ffs
+
 /**
  * find_next_zero_bit - find the first zero bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
  */
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
diff -urN linux-2.4.21-pre1/include/asm-cris/byteorder.h linux-2.4.21-pre2/include/asm-cris/byteorder.h
--- linux-2.4.21-pre1/include/asm-cris/byteorder.h	Thu Feb  8 16:32:44 2001
+++ linux-2.4.21-pre2/include/asm-cris/byteorder.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: byteorder.h,v 1.2 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef _CRIS_BYTEORDER_H
 #define _CRIS_BYTEORDER_H
@@ -12,14 +12,14 @@
  * them together into ntohl etc.
  */
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+extern __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
 	__asm__ ("swapwb %0" : "=r" (x) : "0" (x));
   
 	return(x);
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+extern __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
 	__asm__ ("swapb %0" : "=r" (x) : "0" (x));
 	
diff -urN linux-2.4.21-pre1/include/asm-cris/checksum.h linux-2.4.21-pre2/include/asm-cris/checksum.h
--- linux-2.4.21-pre1/include/asm-cris/checksum.h	Mon Oct  8 11:43:54 2001
+++ linux-2.4.21-pre2/include/asm-cris/checksum.h	Wed Dec 18 14:16:28 2002
@@ -32,7 +32,7 @@
  *	Fold a partial checksum into a word
  */
 
-static inline unsigned int csum_fold(unsigned int sum)
+extern inline unsigned int csum_fold(unsigned int sum)
 {
 	/* the while loop is unnecessary really, it's always enough with two
 	   iterations */
@@ -50,7 +50,7 @@
  * to split all of those into 16-bit components, then add.
  */
 
-static inline unsigned int
+extern inline unsigned int
 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
 		   unsigned short proto, unsigned int sum)
 {
@@ -78,7 +78,7 @@
  *
  */
 
-static inline unsigned short ip_fast_csum(unsigned char * iph,
+extern inline unsigned short ip_fast_csum(unsigned char * iph,
 					  unsigned int ihl)
 {
 	return csum_fold(csum_partial(iph, ihl * 4, 0));
@@ -89,7 +89,7 @@
  * returns a 16-bit checksum, already complemented
  */
 
-static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
 						   unsigned long daddr,
 						   unsigned short len,
 						   unsigned short proto,
@@ -103,7 +103,7 @@
  * in icmp.c
  */
 
-static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
 	return csum_fold (csum_partial(buff, len, 0));
 }
 
diff -urN linux-2.4.21-pre1/include/asm-cris/current.h linux-2.4.21-pre2/include/asm-cris/current.h
--- linux-2.4.21-pre1/include/asm-cris/current.h	Mon Oct  8 11:43:54 2001
+++ linux-2.4.21-pre2/include/asm-cris/current.h	Wed Dec 18 14:16:28 2002
@@ -3,7 +3,7 @@
 
 struct task_struct;
 
-static inline struct task_struct * get_current(void)
+extern inline struct task_struct * get_current(void)
 {
         struct task_struct *current;
         __asm__("and.d $sp,%0; ":"=r" (current) : "0" (~8191UL));
diff -urN linux-2.4.21-pre1/include/asm-cris/ide.h linux-2.4.21-pre2/include/asm-cris/ide.h
--- linux-2.4.21-pre1/include/asm-cris/ide.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-cris/ide.h	Wed Dec 18 14:16:28 2002
@@ -22,9 +22,7 @@
 
 #define MAX_HWIFS	4
 
-#define ide__sti()	__sti()
-
-static __inline__ int ide_default_irq(ide_ioreg_t base)
+extern __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	/* all IDE busses share the same IRQ, number 4.
 	 * this has the side-effect that ide-probe.c will cluster our 4 interfaces
@@ -34,7 +32,7 @@
 	return 4; 
 }
 
-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	/* we have no real I/O base address per interface, since all go through the
 	 * same register. but in a bitfield in that register, we have the i/f number.
@@ -53,7 +51,7 @@
  * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us.
  */
 
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	int i;
 
@@ -76,7 +74,7 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-static __inline__ void ide_init_default_hwifs(void)
+extern __inline__ void ide_init_default_hwifs(void)
 {
 	hw_regs_t hw;
 	int index;
@@ -88,67 +86,11 @@
 	}
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all                    : 8;    /* all of the bits together */
-	struct {
-		unsigned bit0           : 1;
-		unsigned nIEN           : 1;    /* device INTRQ to host */
-		unsigned SRST           : 1;    /* host soft reset bit */
-		unsigned bit3           : 1;    /* ATA-2 thingy */
-		unsigned reserved456    : 3;
-		unsigned HOB            : 1;    /* 48-bit address ordering */
-	} b;
-} control_t;
-
 /* some configuration options we don't need */
 
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS	0
-
-/* request and free a normal interrupt */
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-
-/* ide-probe.c calls ide_request_region and stuff on the io_ports defined,
- * but since they are not actually memory-mapped in the ETRAX driver, we don't
- * do anything.
- */
-
-#define ide_check_region(from,extent)		(0)
-#define ide_request_region(from,extent,name)	do {} while(0)
-#define ide_release_region(from,extent)		do {} while(0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
-/* the drive addressing is done through a controller register on the Etrax CPU */
-void OUT_BYTE(unsigned char data, ide_ioreg_t reg);
-unsigned char IN_BYTE(ide_ioreg_t reg);
-
-/* this tells ide.h not to define the standard macros */
-#define HAVE_ARCH_OUT_BYTE
-#define HAVE_ARCH_IN_BYTE
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMCRIS_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-cris/io.h linux-2.4.21-pre2/include/asm-cris/io.h
--- linux-2.4.21-pre1/include/asm-cris/io.h	Mon Oct  8 11:43:54 2001
+++ linux-2.4.21-pre2/include/asm-cris/io.h	Wed Dec 18 14:16:28 2002
@@ -3,6 +3,8 @@
 
 #include <asm/page.h>   /* for __va, __pa */
 #include <asm/svinto.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
 #include <linux/config.h>
 
 /* Console I/O for simulated etrax100.  Use #ifdef so erroneous
@@ -199,16 +201,18 @@
  * Change virtual addresses to physical addresses and vv.
  */
 
-static inline unsigned long virt_to_phys(volatile void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
-static inline void * phys_to_virt(unsigned long address)
+extern inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
 }
 
+#define page_to_phys(page)	__pa(__page_address(page))
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
@@ -216,6 +220,8 @@
 	return __ioremap(offset, size, 0);
 }
 
+extern void iounmap(void *addr);
+
 /*
  * IO bus memory addresses are also 1:1 with the physical address
  */
diff -urN linux-2.4.21-pre1/include/asm-cris/mmu_context.h linux-2.4.21-pre2/include/asm-cris/mmu_context.h
--- linux-2.4.21-pre1/include/asm-cris/mmu_context.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.21-pre2/include/asm-cris/mmu_context.h	Wed Dec 18 14:16:28 2002
@@ -15,7 +15,7 @@
 
 extern volatile pgd_t *current_pgd;   /* defined in arch/cris/mm/fault.c */
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+extern inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
 
diff -urN linux-2.4.21-pre1/include/asm-cris/pgalloc.h linux-2.4.21-pre2/include/asm-cris/pgalloc.h
--- linux-2.4.21-pre1/include/asm-cris/pgalloc.h	Tue May  1 16:05:00 2001
+++ linux-2.4.21-pre2/include/asm-cris/pgalloc.h	Wed Dec 18 14:16:28 2002
@@ -58,7 +58,7 @@
         pgtable_cache_size++;
 }
 
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
         pte_t *pte;
 
@@ -68,7 +68,7 @@
         return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
         unsigned long *ret;
 
@@ -80,14 +80,14 @@
         return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+extern __inline__ void pte_free_fast(pte_t *pte)
 {
         *(unsigned long *)pte = (unsigned long) pte_quicklist;
         pte_quicklist = (unsigned long *) pte;
         pgtable_cache_size++;
 }
 
-static __inline__ void pte_free_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
 {
         free_page((unsigned long)pte);
 }
diff -urN linux-2.4.21-pre1/include/asm-cris/pgtable.h linux-2.4.21-pre2/include/asm-cris/pgtable.h
--- linux-2.4.21-pre1/include/asm-cris/pgtable.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-cris/pgtable.h	Wed Dec 18 14:16:28 2002
@@ -3,6 +3,12 @@
  * HISTORY:
  *
  * $Log: pgtable.h,v $
+ * Revision 1.17  2002/12/02 08:14:08  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.16  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.15  2002/04/23 15:37:52  bjornw
  * Removed page_address and added flush_icache_user_range
  *
@@ -149,14 +155,14 @@
 			    unsigned long start,
 			    unsigned long end);
 
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
                                       unsigned long start, unsigned long end)
 {
         /* CRIS does not keep any page table caches in TLB */
 }
 
 
-static inline void flush_tlb(void) 
+extern inline void flush_tlb(void) 
 {
 	flush_tlb_mm(current->mm);
 }
@@ -166,6 +172,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 doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -303,53 +311,53 @@
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-static inline int pgd_none(pgd_t pgd)		{ return 0; }
-static inline int pgd_bad(pgd_t pgd)		{ return 0; }
-static inline int pgd_present(pgd_t pgd)	{ return 1; }
-static inline void pgd_clear(pgd_t * pgdp)	{ }
+extern inline int pgd_none(pgd_t pgd)		{ return 0; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
 
-static inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
-static inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
+extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 
-static inline pte_t pte_wrprotect(pte_t pte)
+extern inline pte_t pte_wrprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
         return pte;
 }
 
-static inline pte_t pte_rdprotect(pte_t pte)
+extern inline pte_t pte_rdprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_exprotect(pte_t pte)
+extern inline pte_t pte_exprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkclean(pte_t pte)
+extern inline pte_t pte_mkclean(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); 
 	return pte; 
 }
 
-static inline pte_t pte_mkold(pte_t pte)
+extern inline pte_t pte_mkold(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkwrite(pte_t pte)
+extern inline pte_t pte_mkwrite(pte_t pte)
 {
         pte_val(pte) |= _PAGE_WRITE;
         if (pte_val(pte) & _PAGE_MODIFIED)
@@ -357,7 +365,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkread(pte_t pte)
+extern inline pte_t pte_mkread(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -365,7 +373,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkexec(pte_t pte)
+extern inline pte_t pte_mkexec(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -373,7 +381,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkdirty(pte_t pte)
+extern inline pte_t pte_mkdirty(pte_t pte)
 {
         pte_val(pte) |= _PAGE_MODIFIED;
         if (pte_val(pte) & _PAGE_WRITE)
@@ -381,7 +389,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkyoung(pte_t pte)
+extern inline pte_t pte_mkyoung(pte_t pte)
 {
         pte_val(pte) |= _PAGE_ACCESSED;
         if (pte_val(pte) & _PAGE_READ)
@@ -405,7 +413,7 @@
  * addresses (the 0xc0xxxxxx's) goes as void *'s.
  */
 
-static inline pte_t __mk_pte(void * page, pgprot_t pgprot)
+extern inline pte_t __mk_pte(void * page, pgprot_t pgprot)
 {
 	pte_t pte;
 	/* the PTE needs a physical address */
@@ -423,7 +431,7 @@
         __pte;                                                          \
 })
 
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 
@@ -432,7 +440,7 @@
  * pte_pagenr refers to the page-number counted starting from the virtual DRAM start
  */
 
-static inline unsigned long __pte_page(pte_t pte)
+extern inline unsigned long __pte_page(pte_t pte)
 {
 	/* the PTE contains a physical address */
 	return (unsigned long)__va(pte_val(pte) & PAGE_MASK);
@@ -450,17 +458,17 @@
  * don't need the __pa and __va transformations.
  */
 
-static inline unsigned long pmd_page(pmd_t pmd)
+extern inline unsigned long pmd_page(pmd_t pmd)
 { return pmd_val(pmd) & PAGE_MASK; }
 
-static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; }
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
 /* to find an entry in a page-table-directory */
-static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + pgd_index(address);
 }
@@ -469,13 +477,13 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
 	return (pmd_t *) dir;
 }
 
 /* Find an entry in the third-level page table.. */ 
-static inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
 {
 	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
@@ -495,7 +503,7 @@
  * 
  * Actually I am not sure on what this could be used for.
  */
-static inline void update_mmu_cache(struct vm_area_struct * vma,
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
 	unsigned long address, pte_t pte)
 {
 }
diff -urN linux-2.4.21-pre1/include/asm-cris/posix_types.h linux-2.4.21-pre2/include/asm-cris/posix_types.h
--- linux-2.4.21-pre1/include/asm-cris/posix_types.h	Thu Feb  8 16:32:44 2001
+++ linux-2.4.21-pre2/include/asm-cris/posix_types.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: posix_types.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: posix_types.h,v 1.2 2002/09/26 14:44:59 hp Exp $ */
 
 /* We cheat a bit and use our C-coded bitops functions from asm/bitops.h */
 /* I guess we should write these in assembler because they are used often. */
@@ -23,7 +23,7 @@
 typedef unsigned short  __kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
+typedef __SIZE_TYPE__	__kernel_size_t;
 typedef long		__kernel_ssize_t;
 typedef int		__kernel_ptrdiff_t;
 typedef long		__kernel_time_t;
diff -urN linux-2.4.21-pre1/include/asm-cris/processor.h linux-2.4.21-pre2/include/asm-cris/processor.h
--- linux-2.4.21-pre1/include/asm-cris/processor.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-cris/processor.h	Wed Dec 18 14:16:28 2002
@@ -116,13 +116,13 @@
  * Free current thread data structures etc..
  */
 
-static inline void exit_thread(void)
+extern inline void exit_thread(void)
 {
         /* Nothing needs to be done.  */
 }
 
 /* Free all resources held by a thread. */
-static inline void release_thread(struct task_struct *dead_task)
+extern inline void release_thread(struct task_struct *dead_task)
 {
         /* Nothing needs to be done.  */
 }
diff -urN linux-2.4.21-pre1/include/asm-cris/rtc.h linux-2.4.21-pre2/include/asm-cris/rtc.h
--- linux-2.4.21-pre1/include/asm-cris/rtc.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-cris/rtc.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: rtc.h,v 1.5 2002/08/14 11:04:10 sebsjo Exp $ */
+/* $Id: rtc.h,v 1.8 2002/11/20 14:27:25 oskarp Exp $ */
 
 #ifndef __RTC_H__
 #define __RTC_H__
@@ -53,17 +53,23 @@
 #  define RTC_MINUTE_ALARM	0x09
 #  define RTC_HOUR_ALARM	0x0a
 #  define RTC_DAY_ALARM		0x0b
-#  define RTC_WEEKDAY_ALARM 0x0c
+#  define RTC_WEEKDAY_ALARM 0x0c	/* Not coded in BCD! */
 
 #endif
 
 #ifdef CONFIG_ETRAX_DS1302
+extern unsigned char ds1302_readreg(int reg);
+extern void ds1302_writereg(int reg, unsigned char val);
+extern int ds1302_init(void);
 #  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)
+extern unsigned char pcf8563_readreg(int reg);
+extern void pcf8563_writereg(int reg, unsigned char val);
+extern int pcf8563_init(void);
+#  define CMOS_READ(x) pcf8563_readreg(x)
+#  define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val)
 #  define RTC_INIT() pcf8563_init()
 #else
   /* No RTC configured so we shouldn't try to access any. */
@@ -94,17 +100,10 @@
 };
 
 /* 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
+#define RTC_MAGIC 'p'
+#define RTC_RD_TIME		_IOR(RTC_MAGIC, 0x09, struct rtc_time)	/* Read RTC time. */
+#define RTC_SET_TIME		_IOW(RTC_MAGIC, 0x0a, struct rtc_time)	/* Set RTC time. */
+#define RTC_SET_CHARGE  	_IOW(RTC_MAGIC, 0x0b, int) 		
+#define RTC_MAX_IOCTL 0x0b
 
 #endif /* __RTC_H__ */
diff -urN linux-2.4.21-pre1/include/asm-cris/scatterlist.h linux-2.4.21-pre2/include/asm-cris/scatterlist.h
--- linux-2.4.21-pre1/include/asm-cris/scatterlist.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/include/asm-cris/scatterlist.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRIS_SCATTERLIST_H
+#define __ASM_CRIS_SCATTERLIST_H
+
+struct scatterlist {
+	char *  address;    /* Location data is to be transferred to */
+	unsigned int length;
+
+	/* The following is i386 highmem junk - not used by us */
+	struct page * page; /* Location for highmem page, if any */
+	unsigned int offset;/* for highmem, page offset */
+
+};
+
+/* i386 junk */
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_CRIS_SCATTERLIST_H) */
diff -urN linux-2.4.21-pre1/include/asm-cris/semaphore-helper.h linux-2.4.21-pre2/include/asm-cris/semaphore-helper.h
--- linux-2.4.21-pre1/include/asm-cris/semaphore-helper.h	Tue May  1 16:05:00 2001
+++ linux-2.4.21-pre2/include/asm-cris/semaphore-helper.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $
+/* $Id: semaphore-helper.h,v 1.4 2002/11/20 18:20:17 hp Exp $
  *
  * SMP- and interrupt-safe semaphores helper functions. Generic versions, no
  * optimizations whatsoever... 
@@ -19,12 +19,12 @@
 /*
  * These two _must_ execute atomically wrt each other.
  */
-static inline void wake_one_more(struct semaphore * sem)
+extern inline void wake_one_more(struct semaphore * sem)
 {
 	atomic_inc(&sem->waking);
 }
 
-static inline int waking_non_zero(struct semaphore *sem)
+extern inline int waking_non_zero(struct semaphore *sem)
 {
 	unsigned long flags;
 	int ret = 0;
@@ -38,7 +38,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_interruptible(struct semaphore *sem,
+extern inline int waking_non_zero_interruptible(struct semaphore *sem,
 						struct task_struct *tsk)
 {
 	int ret = 0;
@@ -56,7 +56,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_trylock(struct semaphore *sem)
+extern inline int waking_non_zero_trylock(struct semaphore *sem)
 {
         int ret = 1;
 	unsigned long flags;
diff -urN linux-2.4.21-pre1/include/asm-cris/semaphore.h linux-2.4.21-pre2/include/asm-cris/semaphore.h
--- linux-2.4.21-pre1/include/asm-cris/semaphore.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-cris/semaphore.h	Wed Dec 18 14:16:28 2002
@@ -1,4 +1,4 @@
-/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */
+/* $Id: semaphore.h,v 1.5 2002/12/02 08:14:08 starvik Exp $ */
 
 /* On the i386 these are coded in asm, perhaps we should as well. Later.. */
 
@@ -54,12 +54,12 @@
 	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
 }
 
-static inline void init_MUTEX (struct semaphore *sem)
+extern inline void init_MUTEX (struct semaphore *sem)
 {
         sema_init(sem, 1);
 }
 
-static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+extern inline void init_MUTEX_LOCKED (struct semaphore *sem)
 {
         sema_init(sem, 0);
 }
diff -urN linux-2.4.21-pre1/include/asm-cris/sv_addr_ag.h linux-2.4.21-pre2/include/asm-cris/sv_addr_ag.h
--- linux-2.4.21-pre1/include/asm-cris/sv_addr_ag.h	Thu Feb  8 16:32:44 2001
+++ linux-2.4.21-pre2/include/asm-cris/sv_addr_ag.h	Wed Dec 18 14:16:28 2002
@@ -25,33 +25,41 @@
 
 /* IO_MASK returns a mask for a specified bitfield in a register.
    Note that this macro doesn't work when field width is 32 bits. */
-#define IO_MASK(reg,field) \
-    ( ( ( 1 << reg##__##field##__WIDTH ) - 1 ) << reg##__##field##__BITNR )
+#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_)
+#define IO_MASK_(reg_, field_) \
+    ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR )
 
 /* IO_STATE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Shifted to correct position)  */
-#define IO_STATE(reg,field,state) \
-    ( reg##__##field##__##state << reg##__##field##__BITNR )
+#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state)
+#define IO_STATE_(reg_, field_, _state) \
+    ( reg_##_##field_##_state << reg_##_##field_##_BITNR )
 
 /* IO_EXTRACT returns the masked and shifted value corresponding to the
    bitfield can have. */
-#define IO_EXTRACT(reg,field,val) ( (( ( ( 1 << reg##__##field##__WIDTH ) \
-     - 1 ) << reg##__##field##__BITNR ) & (val)) >> reg##__##field##__BITNR )
+#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val)
+#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \
+     - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR )
 
 /* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Not shifted)  */
-#define IO_STATE_VALUE(reg,field,state) ( reg##__##field##__##state )
+#define IO_STATE_VALUE(reg, field, state) \
+    IO_STATE_VALUE_ (reg##_, field##_, _##state)
+#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state )
 
 /* IO_FIELD shifts the val parameter to be aligned with the bitfield
    specified. */
-#define IO_FIELD(reg,field,val) ((val) << reg##__##field##__BITNR)
+#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val)
+#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR)
 
 /* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is
    LSB and the returned bitnumber is LSB of the field. */
-#define IO_BITNR(reg,field) (reg##__##field##__BITNR)
+#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_)
+#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR)
 
 /* IO_WIDTH returns the width, in bits, of a bitfield. */
-#define IO_WIDTH(reg,field) (reg##__##field##__WIDTH)
+#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_)
+#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH)
 
 /*--- Obsolete. Kept for backw compatibility. ---*/
 /* Reads (or writes) a byte/uword/udword from the specified mode
@@ -66,7 +74,9 @@
 !*-----------------------------------------------------------*/
 
 #define MEM_CSE0_START (0x00000000)
+#define MEM_CSE0_SIZE (0x04000000)
 #define MEM_CSE1_START (0x04000000)
+#define MEM_CSE1_SIZE (0x04000000)
 #define MEM_CSR0_START (0x08000000)
 #define MEM_CSR1_START (0x0c000000)
 #define MEM_CSP0_START (0x10000000)
diff -urN linux-2.4.21-pre1/include/asm-cris/system.h linux-2.4.21-pre2/include/asm-cris/system.h
--- linux-2.4.21-pre1/include/asm-cris/system.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-cris/system.h	Wed Dec 18 14:16:28 2002
@@ -16,7 +16,7 @@
 
 /* read the CPU version register */
 
-static inline unsigned long rdvr(void) { 
+extern inline unsigned long rdvr(void) { 
 	unsigned char vr;
 	__asm__ volatile ("move $vr,%0" : "=rm" (vr));
 	return vr;
@@ -24,7 +24,7 @@
 
 /* read/write the user-mode stackpointer */
 
-static inline unsigned long rdusp(void) {
+extern inline unsigned long rdusp(void) {
 	unsigned long usp;
 	__asm__ __volatile__("move $usp,%0" : "=rm" (usp));
 	return usp;
@@ -35,13 +35,13 @@
 
 /* read the current stackpointer */
 
-static inline unsigned long rdsp(void) {
+extern inline unsigned long rdsp(void) {
 	unsigned long sp;
 	__asm__ __volatile__("move.d $sp,%0" : "=rm" (sp));
 	return sp;
 }
 
-static inline unsigned long _get_base(char * addr)
+extern inline unsigned long _get_base(char * addr)
 {
   return 0;
 }
@@ -84,7 +84,7 @@
 #define save_and_cli(x) do { save_flags(x); cli(); } while(0)
 #define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
-static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
+extern inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
   /* since Etrax doesn't have any atomic xchg instructions, we need to disable
      irq's (if enabled) and do it with move.d's */
diff -urN linux-2.4.21-pre1/include/asm-cris/timex.h linux-2.4.21-pre2/include/asm-cris/timex.h
--- linux-2.4.21-pre1/include/asm-cris/timex.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-cris/timex.h	Wed Dec 18 14:16:28 2002
@@ -26,7 +26,7 @@
 
 unsigned long get_ns_in_jiffie(void);
 
-static inline unsigned long get_us_in_jiffie_highres(void)
+extern inline unsigned long get_us_in_jiffie_highres(void)
 {
 	return get_ns_in_jiffie()/1000;
 }
@@ -37,7 +37,7 @@
 
 typedef unsigned int cycles_t;
 
-static inline cycles_t get_cycles(void)
+extern inline cycles_t get_cycles(void)
 {
         return 0;
 }
diff -urN linux-2.4.21-pre1/include/asm-cris/uaccess.h linux-2.4.21-pre2/include/asm-cris/uaccess.h
--- linux-2.4.21-pre1/include/asm-cris/uaccess.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.21-pre2/include/asm-cris/uaccess.h	Wed Dec 18 14:16:28 2002
@@ -3,6 +3,9 @@
  *	       Hans-Peter Nilsson (hp@axis.com)
  *
  * $Log: uaccess.h,v $
+ * Revision 1.9  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.8  2001/10/29 13:01:48  bjornw
  * Removed unused variable tmp2 in strnlen_user
  *
@@ -321,7 +324,7 @@
  * (without the null byte)
  */
 
-static inline long         
+extern inline long         
 __do_strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res;
@@ -381,7 +384,7 @@
 	return res;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -389,7 +392,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_READ, from, n))
@@ -397,7 +400,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user(void *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -405,13 +408,13 @@
 	return n;
 }
 
-static inline long
+extern inline long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
 	return __do_strncpy_from_user(dst, src, count);
 }
 
-static inline long
+extern inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res = -EFAULT;
@@ -871,7 +874,7 @@
 /* Note that if these expand awfully if made into switch constructs, so
    don't do that.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -921,7 +924,7 @@
 
 /* Ditto, don't make a switch out of this.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -971,7 +974,7 @@
 
 /* No switch, please.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_clear_user(void *to, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -1026,19 +1029,19 @@
  * used in fast paths and have only a small space overhead.
  */
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user_zeroing(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user_nocheck(void *to, unsigned long n)
 {
 	return __do_clear_user(to,n);
@@ -1057,7 +1060,7 @@
  * or 0 for error.  Return a value greater than N if too long.
  */
 
-static inline long
+extern inline long
 strnlen_user(const char *s, long n)
 {
 	long res, tmp1;
diff -urN linux-2.4.21-pre1/include/asm-cris/unistd.h linux-2.4.21-pre2/include/asm-cris/unistd.h
--- linux-2.4.21-pre1/include/asm-cris/unistd.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-cris/unistd.h	Wed Dec 18 14:16:28 2002
@@ -230,18 +230,51 @@
 #define __NR_security           223     /* syscall for security modules */
 #define __NR_gettid             224
 #define __NR_readahead          225
-#define __NR_tkill              226
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
+#define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
+#define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+#define __NR_alloc_hugepages	250
+#define __NR_free_hugepages	251
+#define __NR_exit_group		252
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+/*
+ * Don't remove the .ifnc tests; they are an insurance against
+ * any hard-to-spot gcc register allocation bugs.
+ */
 #define _syscall0(type,name) \
 type name(void) \
 { \
   register long __a __asm__ ("r10"); \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -251,11 +284,14 @@
 type name(type1 arg1) \
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -266,11 +302,14 @@
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3,$r10$r9$r11\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -282,11 +321,14 @@
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4,$r10$r9$r11$r12\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b), "r" (__c)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -299,12 +341,15 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -318,13 +363,16 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d), "g" (arg5) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d), "g" (arg5)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -338,13 +386,17 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\tmove %7,$srp\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
+			: "r" (__n_), "0" (__a), "r" (__b), \
 			  "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
-			: "r10", "r9", "srp"); \
-  if(__a >= 0) \
+			: "srp"); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -365,30 +417,40 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
-static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+extern inline _syscall0(int,idle)
+extern inline _syscall0(int,fork)
+extern inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+extern inline _syscall0(int,pause)
+extern inline _syscall0(int,setup)
+extern inline _syscall0(int,sync)
+extern inline _syscall0(pid_t,setsid)
+extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+extern inline _syscall1(int,dup,int,fd)
+extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+extern inline _syscall1(int,close,int,fd)
+
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which has the "noreturn" attribute and will cause
+ * complaints.  We don't want to use -fno-builtin, so just use a
+ * different name when in the kernel.
+ */
+#ifdef __KERNEL__
+#define _exit kernel_syscall_exit
+#endif
+extern inline _syscall1(int,_exit,int,exitcode)
+extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
 
   /* the following are just while developing the elinux port! */
 
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall2(int,socketcall,int,call,unsigned long *,args)
-static inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
-static inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
+extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+extern inline _syscall2(int,socketcall,int,call,unsigned long *,args)
+extern inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
+extern inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
 
-static inline pid_t wait(int * wait_stat)
+extern inline pid_t wait(int * wait_stat)
 {
 	return waitpid(-1,wait_stat,0);
 }
diff -urN linux-2.4.21-pre1/include/asm-generic/ide_iops.h linux-2.4.21-pre2/include/asm-generic/ide_iops.h
--- linux-2.4.21-pre1/include/asm-generic/ide_iops.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/include/asm-generic/ide_iops.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,38 @@
+/* Generic I/O and MEMIO string operations.  */
+
+#define __ide_insw	insw
+#define __ide_insl	insl
+#define __ide_outsw	outsw
+#define __ide_outsl	outsl
+
+static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u16 *)addr = readw(port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u32 *)addr = readl(port);
+		addr += 4;
+	}
+}
+
+static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writew(*(u16 *)addr, port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writel(*(u32 *)addr, port);
+		addr += 4;
+	}
+}
diff -urN linux-2.4.21-pre1/include/asm-i386/fixmap.h linux-2.4.21-pre2/include/asm-i386/fixmap.h
--- linux-2.4.21-pre1/include/asm-i386/fixmap.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-i386/fixmap.h	Wed Dec 18 14:16:28 2002
@@ -64,6 +64,9 @@
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	FIX_F00F,
 #endif
+#ifdef CONFIG_X86_SUMMIT
+	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+#endif 
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -urN linux-2.4.21-pre1/include/asm-i386/ide.h linux-2.4.21-pre2/include/asm-i386/ide.h
--- linux-2.4.21-pre1/include/asm-i386/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-i386/ide.h	Wed Dec 18 14:16:28 2002
@@ -85,6 +85,8 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMi386_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-i386/io_apic.h linux-2.4.21-pre2/include/asm-i386/io_apic.h
--- linux-2.4.21-pre1/include/asm-i386/io_apic.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.21-pre2/include/asm-i386/io_apic.h	Wed Dec 18 14:16:28 2002
@@ -97,7 +97,7 @@
 extern int mp_irq_entries;
 
 /* MP IRQ source entries */
-extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 
 /* non-0 if default (table-less) MP configuration */
 extern int mpc_default_type;
diff -urN linux-2.4.21-pre1/include/asm-i386/mpspec.h linux-2.4.21-pre2/include/asm-i386/mpspec.h
--- linux-2.4.21-pre1/include/asm-i386/mpspec.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-i386/mpspec.h	Wed Dec 18 14:16:28 2002
@@ -198,11 +198,11 @@
 	MP_BUS_PCI,
 	MP_BUS_MCA
 };
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
-extern int mp_bus_id_to_node [MAX_MP_BUSSES];
-extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int *mp_bus_id_to_type;
+extern int *mp_bus_id_to_node;
+extern int *mp_bus_id_to_local;
+extern int *mp_bus_id_to_pci_bus;
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
 extern unsigned long phys_cpu_present_map;
@@ -211,11 +211,9 @@
 extern void get_smp_config (void);
 extern int nr_ioapics;
 extern int apic_version [MAX_APICS];
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 extern int mpc_default_type;
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
diff -urN linux-2.4.21-pre1/include/asm-i386/smpboot.h linux-2.4.21-pre2/include/asm-i386/smpboot.h
--- linux-2.4.21-pre1/include/asm-i386/smpboot.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-i386/smpboot.h	Wed Dec 18 14:16:28 2002
@@ -14,6 +14,8 @@
 extern unsigned char esr_disable;
 extern unsigned char int_delivery_mode;
 extern unsigned int int_dest_addr_mode;
+extern int cyclone_setup(char*);
+
 static inline void detect_clustered_apic(char* oem, char* prod)
 {
 	/*
@@ -25,6 +27,8 @@
 		int_dest_addr_mode = APIC_DEST_PHYSICAL;
 		int_delivery_mode = dest_Fixed;
 		esr_disable = 1;
+		/*Start cyclone clock*/
+		cyclone_setup(0);
 	}
 	else if (!strncmp(oem, "IBM NUMA", 8)){
 		clustered_apic_mode = CLUSTERED_APIC_NUMAQ;
diff -urN linux-2.4.21-pre1/include/asm-i386/system.h linux-2.4.21-pre2/include/asm-i386/system.h
--- linux-2.4.21-pre1/include/asm-i386/system.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-i386/system.h	Wed Dec 18 14:16:28 2002
@@ -322,19 +322,18 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
-#define __save_and_cli(x)  do { __save_flags(x); __cli(); } while(0);
-#define __save_and_sti(x)  do { __save_flags(x); __sti(); } while(0);
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
 
 /* For spinlocks etc */
 #if 0
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
-#define local_irq_set(x)   __asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
-#else 
-#define local_irq_save(x)  __save_and_cli(x)
-#define local_irq_set(x)   __save_and_sti(x)
+#define local_irq_set(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#else
+#define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #endif
 
-
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -urN linux-2.4.21-pre1/include/asm-ia64/acpi.h linux-2.4.21-pre2/include/asm-ia64/acpi.h
--- linux-2.4.21-pre1/include/asm-ia64/acpi.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/acpi.h	Wed Dec 18 14:16:28 2002
@@ -56,7 +56,7 @@
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n"  \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n"  \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
@@ -68,7 +68,7 @@
 		";;\n"                  \
 		"add    r29=r29,r30\n"  \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
@@ -76,24 +76,24 @@
 		";;\n"                  \
 		"(p8) mov %0=-1\n"      \
 		"(p9) mov %0=r0\n"      \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n" \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n" \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
 		"and    r29=-4,r29\n"   \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
 		"and    %0=1,r2\n"      \
 		";;\n"                  \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 const char *acpi_get_sysname (void);
diff -urN linux-2.4.21-pre1/include/asm-ia64/ia32.h linux-2.4.21-pre2/include/asm-ia64/ia32.h
--- linux-2.4.21-pre1/include/asm-ia64/ia32.h	Fri Nov  9 14:26:17 2001
+++ linux-2.4.21-pre2/include/asm-ia64/ia32.h	Wed Dec 18 14:16:28 2002
@@ -73,6 +73,17 @@
        unsigned short exponent;
 };
 
+struct _fpxreg_ia32 {
+        unsigned short significand[4];
+        unsigned short exponent;
+        unsigned short padding[3];
+};
+
+struct _xmmreg_ia32 {
+        unsigned int element[4];
+};
+
+
 struct _fpstate_ia32 {
        unsigned int    cw,
 		       sw,
@@ -82,7 +93,16 @@
 		       dataoff,
 		       datasel;
        struct _fpreg_ia32      _st[8];
-       unsigned int    status;
+       unsigned short  status;
+       unsigned short  magic;          /* 0xffff = regular FPU data only */
+
+       /* FXSR FPU environment */
+       unsigned int         _fxsr_env[6];   /* FXSR FPU env is ignored */
+       unsigned int         mxcsr;
+       unsigned int         reserved;
+       struct _fpxreg_ia32  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
+       struct _xmmreg_ia32  _xmm[8];
+       unsigned int         padding[56];
 };
 
 struct sigcontext_ia32 {
@@ -110,6 +130,44 @@
        unsigned int cr2;
 };
 
+/* user.h */
+/*
+ * IA32 (Pentium III/4) FXSR, SSE support
+ *
+ * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
+ * interacting with the FXSR-format floating point environment.  Floating
+ * point data can be accessed in the regular format in the usual manner,
+ * and both the standard and SIMD floating point data can be accessed via
+ * the new ptrace requests.  In either case, changes to the FPU environment
+ * will be reflected in the task's state as expected.
+ */
+struct ia32_user_i387_struct {
+	int	cwd;
+	int	swd;
+	int	twd;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct ia32_user_fxsr_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	mxcsr;
+	int	reserved;
+	int	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	int	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+	int	padding[56];
+};
+
 /* signal.h */
 #define _IA32_NSIG	       64
 #define _IA32_NSIG_BPW	       32
@@ -443,6 +501,8 @@
 #define IA32_PTRACE_SETREGS	13
 #define IA32_PTRACE_GETFPREGS	14
 #define IA32_PTRACE_SETFPREGS	15
+#define IA32_PTRACE_GETFPXREGS	18
+#define IA32_PTRACE_SETFPXREGS	19
 
 #define ia32_start_thread(regs,new_ip,new_sp) do {				\
 	set_fs(USER_DS);							\
@@ -485,6 +545,18 @@
 extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t);
 extern void ia32_load_segment_descriptors (struct task_struct *task);
 
+#define ia32f2ia64f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \
+	} while(0)
+
+#define ia64f2ia32f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst),  "r"(src) : "memory"); \
+	} while(0)
+
 #endif /* !CONFIG_IA32_SUPPORT */
 
 #endif /* _ASM_IA64_IA32_H */
diff -urN linux-2.4.21-pre1/include/asm-ia64/ide.h linux-2.4.21-pre2/include/asm-ia64/ide.h
--- linux-2.4.21-pre1/include/asm-ia64/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-ia64/ide.h	Wed Dec 18 14:16:28 2002
@@ -86,6 +86,8 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_IA64_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-ia64/io.h linux-2.4.21-pre2/include/asm-ia64/io.h
--- linux-2.4.21-pre1/include/asm-ia64/io.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-ia64/io.h	Wed Dec 18 14:16:28 2002
@@ -13,7 +13,7 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
@@ -261,9 +261,9 @@
 }
 
 /*
- * Unfortunately, some platforms are broken and do not follow the
- * IA-64 architecture specification regarding legacy I/O support.
- * Thus, we have to make these operations platform dependent...
+ * Unfortunately, some platforms are broken and do not follow the IA-64 architecture
+ * specification regarding legacy I/O support.  Thus, we have to make these operations
+ * platform dependent...
  */
 #define __inb		platform_inb
 #define __inw		platform_inw
@@ -272,18 +272,18 @@
 #define __outw		platform_outw
 #define __outl		platform_outl
 
-#define inb		__inb
-#define inw		__inw
-#define inl		__inl
-#define insb		__insb
-#define insw		__insw
-#define insl		__insl
-#define outb		__outb
-#define outw		__outw
-#define outl		__outl
-#define outsb		__outsb
-#define outsw		__outsw
-#define outsl		__outsl
+#define inb(p)		__inb(p)
+#define inw(p)		__inw(p)
+#define inl(p)		__inl(p)
+#define insb(p,d,c)	__insb(p,d,c)
+#define insw(p,d,c)	__insw(p,d,c)
+#define insl(p,d,c)	__insl(p,d,c)
+#define outb(v,p)	__outb(v,p)
+#define outw(v,p)	__outw(v,p)
+#define outl(v,p)	__outl(v,p)
+#define outsb(p,s,c)	__outsb(p,s,c)
+#define outsw(p,s,c)	__outsw(p,s,c)
+#define outsl(p,s,c)	__outsl(p,s,c)
 
 /*
  * The address passed to these functions are ioremap()ped already.
diff -urN linux-2.4.21-pre1/include/asm-ia64/machvec.h linux-2.4.21-pre2/include/asm-ia64/machvec.h
--- linux-2.4.21-pre1/include/asm-ia64/machvec.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/machvec.h	Wed Dec 18 14:16:28 2002
@@ -25,7 +25,7 @@
 typedef void ia64_mv_irq_init_t (void);
 typedef void ia64_mv_pci_fixup_t (int);
 typedef void ia64_mv_pci_enable_device_t (struct pci_dev *);
-typedef unsigned long ia64_mv_map_nr_t (unsigned long);
+typedef unsigned long ia64_mv_map_nr_t (void *);
 typedef void ia64_mv_mca_init_t (void);
 typedef void ia64_mv_mca_handler_t (void);
 typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
@@ -46,7 +46,6 @@
 typedef void ia64_mv_pci_unmap_sg (struct pci_dev *, struct scatterlist *, int, int);
 typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
 typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *);
 typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
 
 /*
@@ -104,7 +103,6 @@
 #  define platform_pci_unmap_sg		ia64_mv.unmap_sg
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
-#  define platform_pci_dma_address	ia64_mv.dma_address
 #  define platform_pci_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
@@ -140,7 +138,6 @@
 	ia64_mv_pci_unmap_sg *unmap_sg;
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
-	ia64_mv_pci_dma_address *dma_address;
 	ia64_mv_pci_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
@@ -177,7 +174,6 @@
 	platform_pci_unmap_sg,			\
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
-	platform_pci_dma_address,		\
 	platform_pci_dma_supported,		\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
@@ -209,7 +205,6 @@
 extern ia64_mv_pci_unmap_sg swiotlb_unmap_sg;
 extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
 extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
-extern ia64_mv_pci_dma_address swiotlb_dma_address;
 extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
 
 /*
@@ -276,9 +271,6 @@
 #ifndef platform_pci_dma_sync_sg
 # define platform_pci_dma_sync_sg	swiotlb_sync_sg
 #endif
-#ifndef platform_pci_dma_address
-# define  platform_pci_dma_address	swiotlb_dma_address
-#endif
 #ifndef platform_pci_dma_supported
 # define  platform_pci_dma_supported	swiotlb_pci_dma_supported
 #endif
diff -urN linux-2.4.21-pre1/include/asm-ia64/machvec_hpzx1.h linux-2.4.21-pre2/include/asm-ia64/machvec_hpzx1.h
--- linux-2.4.21-pre1/include/asm-ia64/machvec_hpzx1.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/machvec_hpzx1.h	Wed Dec 18 14:16:28 2002
@@ -11,7 +11,6 @@
 extern ia64_mv_pci_unmap_single sba_unmap_single;
 extern ia64_mv_pci_map_sg sba_map_sg;
 extern ia64_mv_pci_unmap_sg sba_unmap_sg;
-extern ia64_mv_pci_dma_address sba_dma_address;
 extern ia64_mv_pci_dma_supported sba_dma_supported;
 
 /*
@@ -35,7 +34,6 @@
 #define platform_pci_unmap_sg		sba_unmap_sg
 #define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
 #define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
-#define platform_pci_dma_address	sba_dma_address
 #define platform_pci_dma_supported	sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -urN linux-2.4.21-pre1/include/asm-ia64/machvec_sn1.h linux-2.4.21-pre2/include/asm-ia64/machvec_sn1.h
--- linux-2.4.21-pre1/include/asm-ia64/machvec_sn1.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/machvec_sn1.h	Wed Dec 18 14:16:28 2002
@@ -58,7 +58,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -95,7 +94,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN1_h */
diff -urN linux-2.4.21-pre1/include/asm-ia64/machvec_sn2.h linux-2.4.21-pre2/include/asm-ia64/machvec_sn2.h
--- linux-2.4.21-pre1/include/asm-ia64/machvec_sn2.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/machvec_sn2.h	Wed Dec 18 14:16:28 2002
@@ -58,7 +58,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -95,7 +94,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN2_H */
diff -urN linux-2.4.21-pre1/include/asm-ia64/mc146818rtc.h linux-2.4.21-pre2/include/asm-ia64/mc146818rtc.h
--- linux-2.4.21-pre1/include/asm-ia64/mc146818rtc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/include/asm-ia64/mc146818rtc.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,10 @@
+#ifndef _ASM_IA64_MC146818RTC_H
+#define _ASM_IA64_MC146818RTC_H
+
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+
+/* empty include file to satisfy the include in genrtc.c */
+
+#endif /* _ASM_IA64_MC146818RTC_H */
diff -urN linux-2.4.21-pre1/include/asm-ia64/mca.h linux-2.4.21-pre2/include/asm-ia64/mca.h
--- linux-2.4.21-pre1/include/asm-ia64/mca.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-ia64/mca.h	Wed Dec 18 14:16:28 2002
@@ -103,6 +103,8 @@
 	IA64_MCA_NEW_CONTEXT	=	-1	/* SAL to return to new context */
 };
 
+#define MIN_STATE_AREA_SIZE     57
+
 typedef struct ia64_mca_os_to_sal_state_s {
 	u64		imots_os_status;	/*   OS status to SAL as to what happened
 						 *   with the MCA handling.
diff -urN linux-2.4.21-pre1/include/asm-ia64/mca_asm.h linux-2.4.21-pre2/include/asm-ia64/mca_asm.h
--- linux-2.4.21-pre1/include/asm-ia64/mca_asm.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-ia64/mca_asm.h	Wed Dec 18 14:16:28 2002
@@ -16,6 +16,7 @@
 #define PSR_I		14
 #define	PSR_DT		17
 #define PSR_RT		27
+#define PSR_MC		35
 #define PSR_IT		36
 #define PSR_BN		44
 
@@ -107,6 +108,8 @@
 	;;										\
 	dep	temp1 = 0, temp1, PSR_IC, 1;						\
 	;;										\
+	dep	temp1 = -1, temp1, PSR_MC, 1;						\
+	;;										\
 	movl	temp2 = start_addr;							\
 	mov	cr.ipsr = temp1;							\
 	;;										\
diff -urN linux-2.4.21-pre1/include/asm-ia64/mmu.h linux-2.4.21-pre2/include/asm-ia64/mmu.h
--- linux-2.4.21-pre1/include/asm-ia64/mmu.h	Fri Dec 29 14:07:23 2000
+++ linux-2.4.21-pre2/include/asm-ia64/mmu.h	Wed Dec 18 14:16:28 2002
@@ -1,7 +1,11 @@
 #ifndef __MMU_H
 #define __MMU_H
 
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+/*
+ * Type for a context number.  We declare it volatile to ensure proper ordering when it's
+ * accessed outside of spinlock'd critical sections (e.g., as done in activate_mm() and
+ * init_new_context()).
+ */
+typedef volatile unsigned long mm_context_t;
 
 #endif
diff -urN linux-2.4.21-pre1/include/asm-ia64/mmu_context.h linux-2.4.21-pre2/include/asm-ia64/mmu_context.h
--- linux-2.4.21-pre1/include/asm-ia64/mmu_context.h	Fri Nov  9 14:26:17 2001
+++ linux-2.4.21-pre2/include/asm-ia64/mmu_context.h	Wed Dec 18 14:16:28 2002
@@ -44,26 +44,32 @@
 {
 }
 
-static inline void
-get_new_mmu_context (struct mm_struct *mm)
+static inline mm_context_t
+get_mmu_context (struct mm_struct *mm)
 {
+	mm_context_t context = mm->context;
+
+	if (context)
+		return context;
+
 	spin_lock(&ia64_ctx.lock);
 	{
-		if (ia64_ctx.next >= ia64_ctx.limit)
-			wrap_mmu_context(mm);
-		mm->context = ia64_ctx.next++;
+		/* re-check, now that we've got the lock: */
+		context = mm->context;
+		if (context == 0) {
+			if (ia64_ctx.next >= ia64_ctx.limit)
+				wrap_mmu_context(mm);
+			mm->context = context = ia64_ctx.next++;
+		}
 	}
 	spin_unlock(&ia64_ctx.lock);
-
-}
-
-static inline void
-get_mmu_context (struct mm_struct *mm)
-{
-	if (mm->context == 0)
-		get_new_mmu_context(mm);
+	return context;
 }
 
+/*
+ * Initialize context number to some sane value.  MM is guaranteed to be a brand-new
+ * address-space, so no TLB flushing is needed, ever.
+ */
 static inline int
 init_new_context (struct task_struct *p, struct mm_struct *mm)
 {
@@ -78,13 +84,13 @@
 }
 
 static inline void
-reload_context (struct mm_struct *mm)
+reload_context (mm_context_t context)
 {
 	unsigned long rid;
 	unsigned long rid_incr = 0;
 	unsigned long rr0, rr1, rr2, rr3, rr4;
 
-	rid = mm->context << 3;	/* make space for encoding the region number */
+	rid = context << 3;	/* make space for encoding the region number */
 	rid_incr = 1 << 8;
 
 	/* encode the region id, preferred page size, and VHPT enable bit: */
@@ -103,6 +109,18 @@
 	ia64_insn_group_barrier();
 }
 
+static inline void
+activate_context (struct mm_struct *mm)
+{
+	mm_context_t context;
+
+	do {
+		context = get_mmu_context(mm);
+		reload_context(context);
+		/* in the unlikely event of a TLB-flush by another thread, redo the load: */
+	} while (unlikely(context != mm->context));
+}
+
 /*
  * Switch from address space PREV to address space NEXT.
  */
@@ -110,12 +128,11 @@
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
 	/*
-	 * We may get interrupts here, but that's OK because interrupt
-	 * handlers cannot touch user-space.
+	 * We may get interrupts here, but that's OK because interrupt handlers cannot
+	 * touch user-space.
 	 */
 	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
-	get_mmu_context(next);
-	reload_context(next);
+	activate_context(next);
 }
 
 #define switch_mm(prev_mm,next_mm,next_task,cpu)	activate_mm(prev_mm, next_mm)
diff -urN linux-2.4.21-pre1/include/asm-ia64/offsets.h linux-2.4.21-pre2/include/asm-ia64/offsets.h
--- linux-2.4.21-pre1/include/asm-ia64/offsets.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/offsets.h	Wed Dec 31 16:00:00 1969
@@ -1,142 +0,0 @@
-#ifndef _ASM_IA64_OFFSETS_H
-#define _ASM_IA64_OFFSETS_H
-/*
- * DO NOT MODIFY
- *
- * This file was generated by arch/ia64/tools/print_offsets.awk.
- *
- */
-#define PT_PTRACED_BIT		0
-#define PT_TRACESYS_BIT		1
-#define IA64_TASK_SIZE			3424	/* 0xd60 */
-#define IA64_PT_REGS_SIZE		400	/* 0x190 */
-#define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
-#define IA64_SIGINFO_SIZE		128	/* 0x80 */
-#define IA64_CPU_SIZE			16384	/* 0x4000 */
-#define SIGFRAME_SIZE			2816	/* 0xb00 */
-#define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
-
-#define IA64_TASK_PTRACE_OFFSET		48	/* 0x30 */
-#define IA64_TASK_SIGPENDING_OFFSET	16	/* 0x10 */
-#define IA64_TASK_NEED_RESCHED_OFFSET	40	/* 0x28 */
-#define IA64_TASK_PROCESSOR_OFFSET	96	/* 0x60 */
-#define IA64_TASK_THREAD_OFFSET		992	/* 0x3e0 */
-#define IA64_TASK_THREAD_KSP_OFFSET	992	/* 0x3e0 */
-#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 1616	/* 0x650 */
-#define IA64_TASK_PID_OFFSET		228	/* 0xe4 */
-#define IA64_TASK_MM_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
-#define IA64_PT_REGS_CR_IIP_OFFSET	8	/* 0x8 */
-#define IA64_PT_REGS_CR_IFS_OFFSET	16	/* 0x10 */
-#define IA64_PT_REGS_AR_UNAT_OFFSET	24	/* 0x18 */
-#define IA64_PT_REGS_AR_PFS_OFFSET	32	/* 0x20 */
-#define IA64_PT_REGS_AR_RSC_OFFSET	40	/* 0x28 */
-#define IA64_PT_REGS_AR_RNAT_OFFSET	48	/* 0x30 */
-#define IA64_PT_REGS_AR_BSPSTORE_OFFSET	56	/* 0x38 */
-#define IA64_PT_REGS_PR_OFFSET		64	/* 0x40 */
-#define IA64_PT_REGS_B6_OFFSET		72	/* 0x48 */
-#define IA64_PT_REGS_LOADRS_OFFSET	80	/* 0x50 */
-#define IA64_PT_REGS_R1_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_R2_OFFSET		96	/* 0x60 */
-#define IA64_PT_REGS_R3_OFFSET		104	/* 0x68 */
-#define IA64_PT_REGS_R12_OFFSET		112	/* 0x70 */
-#define IA64_PT_REGS_R13_OFFSET		120	/* 0x78 */
-#define IA64_PT_REGS_R14_OFFSET		128	/* 0x80 */
-#define IA64_PT_REGS_R15_OFFSET		136	/* 0x88 */
-#define IA64_PT_REGS_R8_OFFSET		144	/* 0x90 */
-#define IA64_PT_REGS_R9_OFFSET		152	/* 0x98 */
-#define IA64_PT_REGS_R10_OFFSET		160	/* 0xa0 */
-#define IA64_PT_REGS_R11_OFFSET		168	/* 0xa8 */
-#define IA64_PT_REGS_R16_OFFSET		176	/* 0xb0 */
-#define IA64_PT_REGS_R17_OFFSET		184	/* 0xb8 */
-#define IA64_PT_REGS_R18_OFFSET		192	/* 0xc0 */
-#define IA64_PT_REGS_R19_OFFSET		200	/* 0xc8 */
-#define IA64_PT_REGS_R20_OFFSET		208	/* 0xd0 */
-#define IA64_PT_REGS_R21_OFFSET		216	/* 0xd8 */
-#define IA64_PT_REGS_R22_OFFSET		224	/* 0xe0 */
-#define IA64_PT_REGS_R23_OFFSET		232	/* 0xe8 */
-#define IA64_PT_REGS_R24_OFFSET		240	/* 0xf0 */
-#define IA64_PT_REGS_R25_OFFSET		248	/* 0xf8 */
-#define IA64_PT_REGS_R26_OFFSET		256	/* 0x100 */
-#define IA64_PT_REGS_R27_OFFSET		264	/* 0x108 */
-#define IA64_PT_REGS_R28_OFFSET		272	/* 0x110 */
-#define IA64_PT_REGS_R29_OFFSET		280	/* 0x118 */
-#define IA64_PT_REGS_R30_OFFSET		288	/* 0x120 */
-#define IA64_PT_REGS_R31_OFFSET		296	/* 0x128 */
-#define IA64_PT_REGS_AR_CCV_OFFSET	304	/* 0x130 */
-#define IA64_PT_REGS_AR_FPSR_OFFSET	312	/* 0x138 */
-#define IA64_PT_REGS_B0_OFFSET		320	/* 0x140 */
-#define IA64_PT_REGS_B7_OFFSET		328	/* 0x148 */
-#define IA64_PT_REGS_F6_OFFSET		336	/* 0x150 */
-#define IA64_PT_REGS_F7_OFFSET		352	/* 0x160 */
-#define IA64_PT_REGS_F8_OFFSET		368	/* 0x170 */
-#define IA64_PT_REGS_F9_OFFSET		384	/* 0x180 */
-#define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0	/* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8	/* 0x8 */
-#define IA64_SWITCH_STACK_F2_OFFSET	16	/* 0x10 */
-#define IA64_SWITCH_STACK_F3_OFFSET	32	/* 0x20 */
-#define IA64_SWITCH_STACK_F4_OFFSET	48	/* 0x30 */
-#define IA64_SWITCH_STACK_F5_OFFSET	64	/* 0x40 */
-#define IA64_SWITCH_STACK_F10_OFFSET	80	/* 0x50 */
-#define IA64_SWITCH_STACK_F11_OFFSET	96	/* 0x60 */
-#define IA64_SWITCH_STACK_F12_OFFSET	112	/* 0x70 */
-#define IA64_SWITCH_STACK_F13_OFFSET	128	/* 0x80 */
-#define IA64_SWITCH_STACK_F14_OFFSET	144	/* 0x90 */
-#define IA64_SWITCH_STACK_F15_OFFSET	160	/* 0xa0 */
-#define IA64_SWITCH_STACK_F16_OFFSET	176	/* 0xb0 */
-#define IA64_SWITCH_STACK_F17_OFFSET	192	/* 0xc0 */
-#define IA64_SWITCH_STACK_F18_OFFSET	208	/* 0xd0 */
-#define IA64_SWITCH_STACK_F19_OFFSET	224	/* 0xe0 */
-#define IA64_SWITCH_STACK_F20_OFFSET	240	/* 0xf0 */
-#define IA64_SWITCH_STACK_F21_OFFSET	256	/* 0x100 */
-#define IA64_SWITCH_STACK_F22_OFFSET	272	/* 0x110 */
-#define IA64_SWITCH_STACK_F23_OFFSET	288	/* 0x120 */
-#define IA64_SWITCH_STACK_F24_OFFSET	304	/* 0x130 */
-#define IA64_SWITCH_STACK_F25_OFFSET	320	/* 0x140 */
-#define IA64_SWITCH_STACK_F26_OFFSET	336	/* 0x150 */
-#define IA64_SWITCH_STACK_F27_OFFSET	352	/* 0x160 */
-#define IA64_SWITCH_STACK_F28_OFFSET	368	/* 0x170 */
-#define IA64_SWITCH_STACK_F29_OFFSET	384	/* 0x180 */
-#define IA64_SWITCH_STACK_F30_OFFSET	400	/* 0x190 */
-#define IA64_SWITCH_STACK_F31_OFFSET	416	/* 0x1a0 */
-#define IA64_SWITCH_STACK_R4_OFFSET	432	/* 0x1b0 */
-#define IA64_SWITCH_STACK_R5_OFFSET	440	/* 0x1b8 */
-#define IA64_SWITCH_STACK_R6_OFFSET	448	/* 0x1c0 */
-#define IA64_SWITCH_STACK_R7_OFFSET	456	/* 0x1c8 */
-#define IA64_SWITCH_STACK_B0_OFFSET	464	/* 0x1d0 */
-#define IA64_SWITCH_STACK_B1_OFFSET	472	/* 0x1d8 */
-#define IA64_SWITCH_STACK_B2_OFFSET	480	/* 0x1e0 */
-#define IA64_SWITCH_STACK_B3_OFFSET	488	/* 0x1e8 */
-#define IA64_SWITCH_STACK_B4_OFFSET	496	/* 0x1f0 */
-#define IA64_SWITCH_STACK_B5_OFFSET	504	/* 0x1f8 */
-#define IA64_SWITCH_STACK_AR_PFS_OFFSET	512	/* 0x200 */
-#define IA64_SWITCH_STACK_AR_LC_OFFSET	520	/* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528	/* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
-#define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
-#define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
-#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
-#define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
-#define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
-#define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
-#define IA64_SIGCONTEXT_AR_UNAT_OFFSET	96	/* 0x60 */
-#define IA64_SIGCONTEXT_B0_OFFSET	136	/* 0x88 */
-#define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
-#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
-#define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
-#define IA64_SIGCONTEXT_PR_OFFSET	128	/* 0x80 */
-#define IA64_SIGCONTEXT_R12_OFFSET	296	/* 0x128 */
-#define IA64_SIGCONTEXT_RBS_BASE_OFFSET	2512	/* 0x9d0 */
-#define IA64_SIGCONTEXT_LOADRS_OFFSET	2520	/* 0x9d8 */
-#define IA64_SIGFRAME_ARG0_OFFSET	0	/* 0x0 */
-#define IA64_SIGFRAME_ARG1_OFFSET	8	/* 0x8 */
-#define IA64_SIGFRAME_ARG2_OFFSET	16	/* 0x10 */
-#define IA64_SIGFRAME_HANDLER_OFFSET	24	/* 0x18 */
-#define IA64_SIGFRAME_SIGCONTEXT_OFFSET	160	/* 0xa0 */
-#define IA64_CLONE_VFORK		16384	/* 0x4000 */
-#define IA64_CLONE_VM			256	/* 0x100 */
-#define IA64_CPU_IRQ_COUNT_OFFSET	0	/* 0x0 */
-#define IA64_CPU_BH_COUNT_OFFSET	4	/* 0x4 */
-#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 12	/* 0xc */
-
-#endif /* _ASM_IA64_OFFSETS_H */
diff -urN linux-2.4.21-pre1/include/asm-ia64/page.h linux-2.4.21-pre2/include/asm-ia64/page.h
--- linux-2.4.21-pre1/include/asm-ia64/page.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/page.h	Wed Dec 18 14:16:28 2002
@@ -65,13 +65,10 @@
 # define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
 # define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 #endif
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-  struct page;
-  extern int ia64_page_valid (struct page *);
-# define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
-#else
-# define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
-#endif
+
+struct page;
+extern int ia64_page_valid (struct page *);
+#define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
 
 typedef union ia64_va {
 	struct {
diff -urN linux-2.4.21-pre1/include/asm-ia64/pal.h linux-2.4.21-pre2/include/asm-ia64/pal.h
--- linux-2.4.21-pre1/include/asm-ia64/pal.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.21-pre2/include/asm-ia64/pal.h	Wed Dec 18 14:16:28 2002
@@ -78,6 +78,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/fpu.h>
 
 /*
  * Data types needed to pass information into PAL procedures and
@@ -650,11 +651,43 @@
 extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64);
 extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64);
 
-#define PAL_CALL(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_static(a0, a1, a2, a3, 0)
-#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1)
-#define PAL_CALL_STK(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_stacked(a0, a1, a2, a3)
-#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_phys_static(a0, a1, a2, a3)
-#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3)
+extern void ia64_save_scratch_fpregs(struct ia64_fpreg *);
+extern void ia64_load_scratch_fpregs(struct ia64_fpreg *);
+
+#define PAL_CALL(iprv,a0,a1,a2,a3) do {                 \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do {          \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_STK(iprv,a0,a1,a2,a3) do {             \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_stacked(a0, a1, a2, a3);   \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) do {            \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_static(a0, a1, a2, a3);\
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) do {        \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
 
 typedef int (*ia64_pal_handler) (u64, ...);
 extern ia64_pal_handler ia64_pal;
diff -urN linux-2.4.21-pre1/include/asm-ia64/pci.h linux-2.4.21-pre2/include/asm-ia64/pci.h
--- linux-2.4.21-pre1/include/asm-ia64/pci.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/pci.h	Wed Dec 18 14:16:28 2002
@@ -26,6 +26,13 @@
 
 struct pci_dev;
 
+/*
+ * 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)
+
 static inline void
 pcibios_set_master (struct pci_dev *dev)
 {
@@ -49,7 +56,6 @@
 #define pci_unmap_sg			platform_pci_unmap_sg
 #define pci_dma_sync_single		platform_pci_dma_sync_single
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
-#define sg_dma_address			platform_pci_dma_address
 #define pci_dma_supported		platform_pci_dma_supported
 
 /* pci_unmap_{single,page} is not a nop, thus... */
@@ -76,7 +82,8 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
-#define sg_dma_len(sg)		((sg)->length)
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->dma_length)
 
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
diff -urN linux-2.4.21-pre1/include/asm-ia64/perfmon.h linux-2.4.21-pre2/include/asm-ia64/perfmon.h
--- linux-2.4.21-pre1/include/asm-ia64/perfmon.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/perfmon.h	Wed Dec 18 14:16:28 2002
@@ -45,6 +45,7 @@
  * PMC flags
  */
 #define PFM_REGFL_OVFL_NOTIFY	0x1	/* send notification on overflow */
+#define PFM_REGFL_RANDOM	0x2	/* randomize sampling interval */
 
 /*
  * PMD/PMC/IBR/DBR return flags (ignored on input)
@@ -85,9 +86,12 @@
 	unsigned long	reg_long_reset;	/* reset after sampling buffer overflow (large) */
 	unsigned long	reg_short_reset;/* reset after counter overflow (small) */
 
-	unsigned long	reg_reset_pmds[4]; /* which other counters to reset on overflow */
+	unsigned long	reg_reset_pmds[4];   /* which other counters to reset on overflow */
+	unsigned long	reg_random_seed;     /* seed value when randomization is used */
+	unsigned long	reg_random_mask;     /* bitmask used to limit random value */
+	unsigned long	reg_last_reset_value;/* last value used to reset the PMD (PFM_READ_PMDS) */
 
-	unsigned long   reserved[16];	/* for future use */
+	unsigned long   reserved[13];	/* for future use */
 } pfarg_reg_t;
 
 typedef struct {
@@ -120,7 +124,7 @@
  * Define the version numbers for both perfmon as a whole and the sampling buffer format.
  */
 #define PFM_VERSION_MAJ		1U
-#define PFM_VERSION_MIN		0U
+#define PFM_VERSION_MIN		2U
 #define PFM_VERSION		(((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
 
 #define PFM_SMPL_VERSION_MAJ	1U
@@ -141,25 +145,29 @@
  * This should be enough for quite some time. Always check sampling format
  * before parsing entries!
  *
- * Inn the case where multiple counters have overflowed at the same time, the 
- * rate field indicate the initial value of the first PMD, based on the index.
- * For instance, if PMD2 and PMD5 have ovewrflowed for this entry, the rate field
- * will show the initial value of PMD2.
+ * In the case where multiple counters overflow at the same time, the
+ * last_reset_value member indicates the initial value of the PMD with
+ * the smallest index.  For instance, if PMD2 and PMD5 have overflowed,
+ * the last_reset_value member contains the initial value of PMD2.
  */
 typedef struct {
-	int		pid;		/* identification of process */
-	int		cpu;		/* which cpu was used */
-	unsigned long	rate;		/* initial value of overflowed counter */
-	unsigned long	stamp;		/* timestamp */
-	unsigned long	ip;		/* where did the overflow interrupt happened */
-	unsigned long	regs;		/* bitmask of which registers overflowed */
-	unsigned long   period;		/* sampling period used by overflowed counter (smallest pmd index) */
+	int		pid;		 /* identification of process */
+	int		cpu;		 /* which cpu was used */
+	unsigned long	last_reset_value;/* initial value of overflowed counter */
+	unsigned long	stamp;		 /* timestamp (unique per CPU) */
+	unsigned long	ip;		 /* where did the overflow interrupt happened */
+	unsigned long	regs;		 /* bitmask of which registers overflowed */
+	unsigned long   period;		 /* sampling period used by overflowed counter (smallest pmd index) */
 } perfmon_smpl_entry_t;
 
 extern int perfmonctl(pid_t pid, int cmd, void *arg, int narg);
 
 #ifdef __KERNEL__
 
+typedef struct {
+	void (*handler)(int irq, void *arg, struct pt_regs *regs);
+} pfm_intr_handler_desc_t;
+
 extern void pfm_save_regs (struct task_struct *);
 extern void pfm_load_regs (struct task_struct *);
 
@@ -172,7 +180,14 @@
 extern int  pfm_release_debug_registers(struct task_struct *);
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
 extern void pfm_syst_wide_update_task(struct task_struct *, int);
-extern void perfmon_init_percpu(void);
+extern void pfm_init_percpu(void);
+
+/* 
+ * hooks to allow VTune/Prospect to cooperate with perfmon.
+ * (reserved for system wide monitoring modules only)
+ */
+extern int pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
+extern int pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.21-pre1/include/asm-ia64/pgalloc.h linux-2.4.21-pre2/include/asm-ia64/pgalloc.h
--- linux-2.4.21-pre1/include/asm-ia64/pgalloc.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/pgalloc.h	Wed Dec 18 14:16:28 2002
@@ -157,29 +157,44 @@
  * Flush everything (kernel mapping may also have changed due to
  * vmalloc/vfree).
  */
-extern void __flush_tlb_all (void);
+extern void local_flush_tlb_all (void);
 
 #ifdef CONFIG_SMP
   extern void smp_flush_tlb_all (void);
+  extern void smp_flush_tlb_mm (struct mm_struct *mm);
 # define flush_tlb_all()	smp_flush_tlb_all()
 #else
-# define flush_tlb_all()	__flush_tlb_all()
+# define flush_tlb_all()	local_flush_tlb_all()
 #endif
 
+static inline void
+local_flush_tlb_mm (struct mm_struct *mm)
+{
+	if (mm == current->active_mm)
+		activate_context(mm);
+}
+
 /*
- * Flush a specified user mapping
+ * Flush a specified user mapping.  This is called, e.g., as a result of fork() and
+ * exit().  fork() ends up here because the copy-on-write mechanism needs to write-protect
+ * the PTEs of the parent task.
  */
 static inline void
 flush_tlb_mm (struct mm_struct *mm)
 {
-	if (mm) {
-		mm->context = 0;
-		if (mm == current->active_mm) {
-			/* This is called, e.g., as a result of exec().  */
-			get_new_mmu_context(mm);
-			reload_context(mm);
-		}
-	}
+	if (!mm)
+		return;
+
+	mm->context = 0;
+
+	if (atomic_read(&mm->mm_users) == 0)
+		return;		/* happens as a result of exit_mmap() */
+
+#ifdef CONFIG_SMP
+	smp_flush_tlb_mm(mm);
+#else
+	local_flush_tlb_mm(mm);
+#endif
 }
 
 extern void flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end);
diff -urN linux-2.4.21-pre1/include/asm-ia64/pgtable.h linux-2.4.21-pre2/include/asm-ia64/pgtable.h
--- linux-2.4.21-pre1/include/asm-ia64/pgtable.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/pgtable.h	Wed Dec 18 14:16:28 2002
@@ -198,13 +198,9 @@
 
 #define VMALLOC_START		(0xa000000000000000 + 3*PAGE_SIZE)
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-# define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
-# define VMALLOC_END             vmalloc_end
-  extern unsigned long vmalloc_end;
-#else
-# define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
-#endif
+#define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
+#define VMALLOC_END             vmalloc_end
+extern unsigned long vmalloc_end;
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -284,11 +280,7 @@
  * works bypasses the caches, but does allow for consecutive writes to
  * be combined into single (but larger) write transactions.
  */
-#ifdef CONFIG_MCKINLEY_A0_SPECIFIC
-# define pgprot_writecombine(prot)	prot
-#else
-# define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
-#endif
+#define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
 
 /*
  * Return the region index for virtual address ADDRESS.
@@ -448,8 +440,6 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
 /* arch mem_map init routines are needed due to holes in a virtual mem_map */
 #define HAVE_ARCH_MEMMAP_INIT
 
@@ -460,8 +450,6 @@
 	struct page *start, struct page *end, int zone,
 	unsigned long start_paddr, int highmem);
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 # endif /* !__ASSEMBLY__ */
 
 /*
diff -urN linux-2.4.21-pre1/include/asm-ia64/processor.h linux-2.4.21-pre2/include/asm-ia64/processor.h
--- linux-2.4.21-pre1/include/asm-ia64/processor.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/processor.h	Wed Dec 18 14:16:28 2002
@@ -167,16 +167,16 @@
 	__u32 ptce_count[2];
 	__u32 ptce_stride[2];
 	struct task_struct *ksoftirqd;	/* kernel softirq daemon for this CPU */
+# ifdef CONFIG_PERFMON
+	__u32 pfm_syst_wide;
+	__u32 pfm_dcr_pp;
+# endif
 #ifdef CONFIG_SMP
 	int processor;
 	__u64 loops_per_jiffy;
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
-# ifdef CONFIG_PERFMON
-	__u32 pfm_syst_wide;
-	__u32 pfm_dcr_pp;
-# endif
 	union {
 		/*
 		 *  This is written to by *other* CPUs,
diff -urN linux-2.4.21-pre1/include/asm-ia64/sal.h linux-2.4.21-pre2/include/asm-ia64/sal.h
--- linux-2.4.21-pre1/include/asm-ia64/sal.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/sal.h	Wed Dec 18 14:16:28 2002
@@ -38,9 +38,12 @@
 
 # define SAL_CALL(result,args...) do {			\
 	unsigned long flags;				\
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                   \
 	spin_lock_irqsave(&sal_lock, flags);		\
 	__SAL_CALL(result,args);			\
 	spin_unlock_irqrestore(&sal_lock, flags);	\
+	ia64_load_scratch_fpregs(fr);                   \
 } while (0)
 
 #define SAL_SET_VECTORS			0x01000000
diff -urN linux-2.4.21-pre1/include/asm-ia64/scatterlist.h linux-2.4.21-pre2/include/asm-ia64/scatterlist.h
--- linux-2.4.21-pre1/include/asm-ia64/scatterlist.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-ia64/scatterlist.h	Wed Dec 18 14:16:28 2002
@@ -9,12 +9,13 @@
 struct scatterlist {
 	/* This will disappear in 2.5.x: */
 	char *address;		/* location data is to be transferred to, NULL for highmem page */
-	char *orig_address;	/* for use by swiotlb */
 
 	/* These two are only valid if ADDRESS member of this struct is NULL.  */
 	struct page *page;
 	unsigned int offset;
 	unsigned int length;	/* buffer length */
+	dma_addr_t dma_address;
+	unsigned int dma_length;
 };
 
 #define ISA_DMA_THRESHOLD	(~0UL)
diff -urN linux-2.4.21-pre1/include/asm-ia64/siginfo.h linux-2.4.21-pre2/include/asm-ia64/siginfo.h
--- linux-2.4.21-pre1/include/asm-ia64/siginfo.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/siginfo.h	Wed Dec 18 14:16:28 2002
@@ -266,8 +266,8 @@
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
 	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+		/* _sigprof is currently the largest know union member */
+		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigprof));
 }
 
 extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
diff -urN linux-2.4.21-pre1/include/asm-ia64/sn/alenlist.h linux-2.4.21-pre2/include/asm-ia64/sn/alenlist.h
--- linux-2.4.21-pre1/include/asm-ia64/sn/alenlist.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-ia64/sn/alenlist.h	Wed Dec 18 14:16:28 2002
@@ -15,7 +15,7 @@
 
 /*
  * An Address/Length List is used when setting up for an I/O DMA operation.
- * A driver creates an Address/Length List that describes to the the DMA 
+ * A driver creates an Address/Length List that describes to the DMA 
  * interface where in memory the DMA should go.  The bus interface sets up 
  * mapping registers, if required, and returns a suitable list of "physical 
  * addresses" or "I/O address" to the driver.  The driver then uses these 
diff -urN linux-2.4.21-pre1/include/asm-ia64/system.h linux-2.4.21-pre2/include/asm-ia64/system.h
--- linux-2.4.21-pre1/include/asm-ia64/system.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-ia64/system.h	Wed Dec 18 14:16:28 2002
@@ -393,7 +393,7 @@
 extern void ia64_save_extra (struct task_struct *task);
 extern void ia64_load_extra (struct task_struct *task);
 
-#if defined(CONFIG_SMP) && defined(CONFIG_PERFMON)
+#ifdef CONFIG_PERFMON
 # define PERFMON_IS_SYSWIDE() (local_cpu_data->pfm_syst_wide != 0)
 #else
 # define PERFMON_IS_SYSWIDE() (0)
diff -urN linux-2.4.21-pre1/include/asm-ia64/unistd.h linux-2.4.21-pre2/include/asm-ia64/unistd.h
--- linux-2.4.21-pre1/include/asm-ia64/unistd.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ia64/unistd.h	Wed Dec 18 14:16:28 2002
@@ -206,12 +206,23 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
-/*
- * 1217-1228: reserved for xattr
- * 1230-1232: reserved for futex and sched_[sg]etaffinity.
- */
+#define __NR_setxattr			1217
+#define __NR_lsetxattr			1218
+#define __NR_fsetxattr			1219
+#define __NR_getxattr			1220
+#define __NR_lgetxattr			1221
+#define __NR_fgetxattr			1222
+#define __NR_listxattr			1223
+#define __NR_llistxattr			1224
+#define __NR_flistxattr			1225
+#define __NR_removexattr		1226
+#define __NR_lremovexattr		1227
+#define __NR_fremovexattr		1228
 #define __NR_tkill			1229
-#define __NR_security			1233 /* syscall for security modules */
+/* 1230-1232: reserved for futex and sched_[sg]etaffinity */
+#define __NR_security			1233
+/* 1234-1235: reserved for {alloc,free}_hugepages */
+/* 1238-1242: reserved for io_{setup,destroy,getevents,submit,cancel} */
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -urN linux-2.4.21-pre1/include/asm-parisc/hdreg.h linux-2.4.21-pre2/include/asm-parisc/hdreg.h
--- linux-2.4.21-pre1/include/asm-parisc/hdreg.h	Tue Dec  5 12:29:39 2000
+++ linux-2.4.21-pre2/include/asm-parisc/hdreg.h	Wed Dec 18 14:16:28 2002
@@ -1,6 +1,7 @@
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif
diff -urN linux-2.4.21-pre1/include/asm-parisc/ide.h linux-2.4.21-pre2/include/asm-parisc/ide.h
--- linux-2.4.21-pre1/include/asm-parisc/ide.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-parisc/ide.h	Wed Dec 18 14:16:28 2002
@@ -20,6 +20,8 @@
 #define MAX_HWIFS	2
 #endif
 
+#define ide__sti()      __sti()
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -78,93 +80,28 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit7		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned head		: 4;	/* always zeros here */
+	} b;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.21-pre1/include/asm-parisc/system_irqsave.h linux-2.4.21-pre2/include/asm-parisc/system_irqsave.h
--- linux-2.4.21-pre1/include/asm-parisc/system_irqsave.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.21-pre2/include/asm-parisc/system_irqsave.h	Wed Dec 18 14:16:28 2002
@@ -0,0 +1,17 @@
+#ifndef __PARISC_SYSTEM_IRQSAVE_H
+#define __PARISC_SYSTEM_IRQSAVE_H
+
+/* interrupt control */
+#define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
+#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
+#define __cli()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+#define __sti()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+
+#define local_irq_save(x) \
+	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
+#define local_irq_restore(x) \
+	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
+#define local_irq_disable() __cli()
+#define local_irq_enable()  __sti()
+
+#endif /* __PARISC_SYSTEM_IRQSAVE_H */
diff -urN linux-2.4.21-pre1/include/asm-ppc/hw_irq.h linux-2.4.21-pre2/include/asm-ppc/hw_irq.h
--- linux-2.4.21-pre1/include/asm-ppc/hw_irq.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ppc/hw_irq.h	Wed Dec 18 14:16:28 2002
@@ -21,6 +21,7 @@
 
 #define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags)
 #define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+#define __save_and_sti(flags) ({__save_flags(flags);__sti();})
 
 extern void do_lost_interrupts(unsigned long);
 
diff -urN linux-2.4.21-pre1/include/asm-ppc/semaphore.h linux-2.4.21-pre2/include/asm-ppc/semaphore.h
--- linux-2.4.21-pre1/include/asm-ppc/semaphore.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/asm-ppc/semaphore.h	Wed Dec 18 14:16:28 2002
@@ -12,7 +12,7 @@
  * -- Ani Joshi (ajoshi@unixbox.com)
  *
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
diff -urN linux-2.4.21-pre1/include/asm-s390/io.h linux-2.4.21-pre2/include/asm-s390/io.h
--- linux-2.4.21-pre1/include/asm-s390/io.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.21-pre2/include/asm-s390/io.h	Wed Dec 18 14:16:28 2002
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -urN linux-2.4.21-pre1/include/asm-s390/rwsem.h linux-2.4.21-pre2/include/asm-s390/rwsem.h
--- linux-2.4.21-pre1/include/asm-s390/rwsem.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-s390/rwsem.h	Wed Dec 18 14:16:28 2002
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: ltr  %1,%0\n"
+		"   jm   1f\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%1)\n"
+		"0: ltr  %0,%0\n"
+		"   jnz  1f\n"
+		"   cs   %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -urN linux-2.4.21-pre1/include/asm-s390x/io.h linux-2.4.21-pre2/include/asm-s390x/io.h
--- linux-2.4.21-pre1/include/asm-s390x/io.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.21-pre2/include/asm-s390x/io.h	Wed Dec 18 14:16:28 2002
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -urN linux-2.4.21-pre1/include/asm-s390x/rwsem.h linux-2.4.21-pre2/include/asm-s390x/rwsem.h
--- linux-2.4.21-pre1/include/asm-s390x/rwsem.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/asm-s390x/rwsem.h	Wed Dec 18 14:16:28 2002
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: ltr  %1,%0\n"
+		"   jm   1f\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%1)\n"
+		"0: ltr  %0,%0\n"
+		"   jnz  1f\n"
+		"   cs   %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -urN linux-2.4.21-pre1/include/asm-sh/ide.h linux-2.4.21-pre2/include/asm-sh/ide.h
--- linux-2.4.21-pre1/include/asm-sh/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-sh/ide.h	Wed Dec 18 14:16:28 2002
@@ -105,6 +105,8 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_IDE_H */
diff -urN linux-2.4.21-pre1/include/asm-sparc64/ide.h linux-2.4.21-pre2/include/asm-sparc64/ide.h
--- linux-2.4.21-pre1/include/asm-sparc64/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-sparc64/ide.h	Wed Dec 18 14:16:28 2002
@@ -76,26 +76,16 @@
 #undef  HD_DATA
 #define HD_DATA ((ide_ioreg_t)0)
 
-/* From m68k code... */
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-#define insw(port, buf, nr) ide_insw((port), (buf), (nr))
-#define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
+#define __ide_insl(data_reg, buffer, wcount) \
+	__ide_insw(data_reg, buffer, (wcount)<<1)
+#define __ide_outsl(data_reg, buffer, wcount) \
+	__ide_outsw(data_reg, buffer, (wcount)<<1)
+
+/* On sparc64, I/O ports and MMIO registers are accessed identically.  */
+#define __ide_mm_insw	__ide_insw
+#define __ide_mm_insl	__ide_insl
+#define __ide_mm_outsw	__ide_outsw
+#define __ide_mm_outsl	__ide_outsl
 
 static __inline__ unsigned int inw_be(unsigned long addr)
 {
@@ -108,9 +98,9 @@
 	return ret;
 }
 
-static __inline__ void ide_insw(unsigned long port,
-				void *dst,
-				unsigned long count)
+static __inline__ void __ide_insw(unsigned long port,
+				  void *dst,
+				  u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)dst + (count << 1);
@@ -147,9 +137,9 @@
 			     : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
 
-static __inline__ void ide_outsw(unsigned long port,
-				 const void *src,
-				 unsigned long count)
+static __inline__ void __ide_outsw(unsigned long port,
+				   void *src,
+				   u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)src + (count << 1);
diff -urN linux-2.4.21-pre1/include/asm-x86_64/ide.h linux-2.4.21-pre2/include/asm-x86_64/ide.h
--- linux-2.4.21-pre1/include/asm-x86_64/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/asm-x86_64/ide.h	Wed Dec 18 14:16:28 2002
@@ -84,6 +84,8 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMx86_64_IDE_H */
diff -urN linux-2.4.21-pre1/include/linux/cciss_ioctl.h linux-2.4.21-pre2/include/linux/cciss_ioctl.h
--- linux-2.4.21-pre1/include/linux/cciss_ioctl.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/linux/cciss_ioctl.h	Wed Dec 18 14:16:28 2002
@@ -73,10 +73,10 @@
 #define TYPE_MSG				0x01
 
 // Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
+typedef __u8 BYTE;
+typedef __u16 WORD; 
+typedef __u16 HWORD; 
+typedef __u32 DWORD; 
 
 #define CISS_MAX_LUN	16	
 
@@ -169,6 +169,18 @@
   BYTE			   *buf;
 } IOCTL_Command_struct;
 
+#define MAX_KMALLOC_SIZE 128000
+
+typedef struct _BIG_IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  DWORD			   malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* < malloc_size * MAXSGENTRIES */
+  BYTE			   *buf;
+} BIG_IOCTL_Command_struct;
+
 typedef struct _LogvolInfo_struct{
    __u32	LunID;
    int		num_opens;  /* number of opens on the logical volume */
@@ -189,7 +201,11 @@
 #define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
 #define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10) /* obsolete */
 #define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK	   _IO(CCISS_IOC_MAGIC, 12)
+#define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, __u64)
+#define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
+#define CCISS_RESCANDISK   _IO(CCISS_IOC_MAGIC, 16)
 #define CCISS_GETLUNINFO  _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
-
+#define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
 #endif  
diff -urN linux-2.4.21-pre1/include/linux/com20020.h linux-2.4.21-pre2/include/linux/com20020.h
--- linux-2.4.21-pre1/include/linux/com20020.h	Sun Aug 12 11:42:31 2001
+++ linux-2.4.21-pre2/include/linux/com20020.h	Wed Dec 18 14:16:28 2002
@@ -32,7 +32,7 @@
 void com20020_remove(struct net_device *dev);
 
 /* The number of low I/O ports used by the card. */
-#define ARCNET_TOTAL_SIZE 9
+#define ARCNET_TOTAL_SIZE 8
 
 /* various register addresses */
 #define _INTMASK  (ioaddr+0)	/* writable */
@@ -59,6 +59,8 @@
 
 /* in SETUP register */
 #define PROMISCset	0x10	/* enable RCV_ALL */
+#define P1MODE          0x80    /* enable P1-MODE for Backplane */
+#define SLOWARB         0x01    /* enable Slow Arbitration for >=5Mbps */
 
 /* COM2002x */
 #define SUB_TENTATIVE	0	/* tentative node ID */
diff -urN linux-2.4.21-pre1/include/linux/ide.h linux-2.4.21-pre2/include/linux/ide.h
--- linux-2.4.21-pre1/include/linux/ide.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/linux/ide.h	Wed Dec 18 14:16:28 2002
@@ -303,17 +303,17 @@
 
 typedef struct ide_io_ops_s {
 	/* insert io operations here! */
-	void (*OUTB)(u8 addr, u32 port);
-	void (*OUTW)(u16 addr, u32 port);
-	void (*OUTL)(u32 addr, u32 port);
-	void (*OUTSW)(u32 port, void *addr, u32 count);
-	void (*OUTSL)(u32 port, void *addr, u32 count);
-
-	u8  (*INB)(u32 port);
-	u16 (*INW)(u32 port);
-	u32 (*INL)(u32 port);
-	void (*INSW)(u32 port, void *addr, u32 count);
-	void (*INSL)(u32 port, void *addr, u32 count);
+	void (*OUTB)(u8 addr, unsigned long port);
+	void (*OUTW)(u16 addr, unsigned long port);
+	void (*OUTL)(u32 addr, unsigned long port);
+	void (*OUTSW)(unsigned long port, void *addr, u32 count);
+	void (*OUTSL)(unsigned long port, void *addr, u32 count);
+
+	u8  (*INB)(unsigned long port);
+	u16 (*INW)(unsigned long port);
+	u32 (*INL)(unsigned long port);
+	void (*INSW)(unsigned long port, void *addr, u32 count);
+	void (*INSL)(unsigned long port, void *addr, u32 count);
 } ide_io_ops_t;
 
 /*
@@ -954,17 +954,17 @@
 #if 0
 	ide_io_ops_t	*iops;
 #else
-	void (*OUTB)(u8 addr, u32 port);
-	void (*OUTW)(u16 addr, u32 port);
-	void (*OUTL)(u32 addr, u32 port);
-	void (*OUTSW)(u32 port, void *addr, u32 count);
-	void (*OUTSL)(u32 port, void *addr, u32 count);
-
-	u8  (*INB)(u32 port);
-	u16 (*INW)(u32 port);
-	u32 (*INL)(u32 port);
-	void (*INSW)(u32 port, void *addr, u32 count);
-	void (*INSL)(u32 port, void *addr, u32 count);
+	void (*OUTB)(u8 addr, unsigned long port);
+	void (*OUTW)(u16 addr, unsigned long port);
+	void (*OUTL)(u32 addr, unsigned long port);
+	void (*OUTSW)(unsigned long port, void *addr, u32 count);
+	void (*OUTSL)(unsigned long port, void *addr, u32 count);
+
+	u8  (*INB)(unsigned long port);
+	u16 (*INW)(unsigned long port);
+	u32 (*INL)(unsigned long port);
+	void (*INSW)(unsigned long port, void *addr, u32 count);
+	void (*INSL)(unsigned long port, void *addr, u32 count);
 #endif
 
 	/* dma physical region descriptor table (cpu view) */
diff -urN linux-2.4.21-pre1/include/linux/interrupt.h linux-2.4.21-pre2/include/linux/interrupt.h
--- linux-2.4.21-pre1/include/linux/interrupt.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.21-pre2/include/linux/interrupt.h	Wed Dec 18 14:16:28 2002
@@ -10,6 +10,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
+#include <asm/system.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
diff -urN linux-2.4.21-pre1/include/linux/miscdevice.h linux-2.4.21-pre2/include/linux/miscdevice.h
--- linux-2.4.21-pre1/include/linux/miscdevice.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/linux/miscdevice.h	Wed Dec 18 14:16:28 2002
@@ -3,38 +3,39 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#define BUSMOUSE_MINOR 0
-#define PSMOUSE_MINOR  1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
-#define AMIGAMOUSE_MINOR 4
-#define ATARIMOUSE_MINOR 5
-#define SUN_MOUSE_MINOR 6
-#define APOLLO_MOUSE_MINOR 7
-#define PC110PAD_MINOR 9
-#define ADB_MOUSE_MINOR 10
-#define MK712_MINOR 15			/* MK712 touch screen */
+#define BUSMOUSE_MINOR		0
+#define PSMOUSE_MINOR		1
+#define MS_BUSMOUSE_MINOR	2
+#define ATIXL_BUSMOUSE_MINOR	3
+#define AMIGAMOUSE_MINOR	4
+#define ATARIMOUSE_MINOR	5
+#define SUN_MOUSE_MINOR		6
+#define APOLLO_MOUSE_MINOR	7
+#define PC110PAD_MINOR		9
+#define ADB_MOUSE_MINOR		10
+#define MK712_MINOR 		15	/* MK712 touch screen */
+#define SYNTH_MINOR    		25
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
-#define RTC_MINOR 135
+#define RTC_MINOR		135
 #define EFI_RTC_MINOR		136	/* EFI Time services */
-#define SUN_OPENPROM_MINOR 139
-#define NVRAM_MINOR 144
-#define I2O_MINOR 166
+#define SUN_OPENPROM_MINOR	139
+#define NVRAM_MINOR		144
+#define I2O_MINOR		166
 #define MICROCODE_MINOR		184
-#define MWAVE_MINOR	219		/* ACP/Mwave Modem */
-#define MPT_MINOR	220
-#define MISC_DYNAMIC_MINOR 255
-
-#define SGI_GRAPHICS_MINOR   146
-#define SGI_OPENGL_MINOR     147
-#define SGI_GFX_MINOR        148
-#define SGI_STREAMS_MOUSE    149
-#define SGI_STREAMS_KEYBOARD 150
+#define MWAVE_MINOR		219	/* ACP/Mwave Modem */
+#define MPT_MINOR		220
+#define MISC_DYNAMIC_MINOR	255
+
+#define SGI_GRAPHICS_MINOR	146
+#define SGI_OPENGL_MINOR	147
+#define SGI_GFX_MINOR		148
+#define SGI_STREAMS_MOUSE	149
+#define SGI_STREAMS_KEYBOARD	150
 /* drivers/sgi/char/usema.c */
-#define SGI_USEMACLONE	     151
+#define SGI_USEMACLONE	    	151
 
-#define TUN_MINOR	     200
+#define TUN_MINOR	     	200
 
 extern int misc_init(void);
 
diff -urN linux-2.4.21-pre1/include/linux/mm.h linux-2.4.21-pre2/include/linux/mm.h
--- linux-2.4.21-pre1/include/linux/mm.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.21-pre2/include/linux/mm.h	Wed Dec 18 14:16:28 2002
@@ -297,6 +297,7 @@
 #define PG_arch_1		13
 #define PG_reserved		14
 #define PG_launder		15	/* written out by VM pressure.. */
+#define PG_fs_1			16	/* Filesystem specific */
 
 /* Make it prettier to test the above... */
 #define UnlockPage(page)	unlock_page(page)
diff -urN linux-2.4.21-pre1/include/linux/nfs_fs.h linux-2.4.21-pre2/include/linux/nfs_fs.h
--- linux-2.4.21-pre1/include/linux/nfs_fs.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/linux/nfs_fs.h	Wed Dec 18 14:16:28 2002
@@ -269,6 +269,10 @@
 extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 
+#define NFS_SetPageSync(page)		set_bit(PG_fs_1, &(page)->flags)
+#define NFS_ClearPageSync(page)		clear_bit(PG_fs_1, &(page)->flags)
+#define NFS_TestClearPageSync(page)	test_and_clear_bit(PG_fs_1, &(page)->flags)
+
 /*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
diff -urN linux-2.4.21-pre1/include/linux/nfsd/const.h linux-2.4.21-pre2/include/linux/nfsd/const.h
--- linux-2.4.21-pre1/include/linux/nfsd/const.h	Sat Apr  1 08:04:27 2000
+++ linux-2.4.21-pre2/include/linux/nfsd/const.h	Wed Dec 18 14:16:28 2002
@@ -21,7 +21,7 @@
 /*
  * Maximum blocksize supported by daemon currently at 8K
  */
-#define NFSSVC_MAXBLKSIZE	8192
+#define NFSSVC_MAXBLKSIZE	(8*1024)
 
 #ifdef __KERNEL__
 
diff -urN linux-2.4.21-pre1/include/linux/pci_ids.h linux-2.4.21-pre2/include/linux/pci_ids.h
--- linux-2.4.21-pre1/include/linux/pci_ids.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/linux/pci_ids.h	Wed Dec 18 14:16:28 2002
@@ -383,7 +383,7 @@
 #define PCI_DEVICE_ID_AMD_FE_GATE_7006	0x7006
 #define PCI_DEVICE_ID_AMD_FE_GATE_7007	0x7007
 #define PCI_DEVICE_ID_AMD_FE_GATE_700C	0x700C
-#define PCI_DEVIDE_ID_AMD_FE_GATE_700D	0x700D
+#define PCI_DEVICE_ID_AMD_FE_GATE_700D	0x700D
 #define PCI_DEVICE_ID_AMD_FE_GATE_700E	0x700E
 #define PCI_DEVICE_ID_AMD_FE_GATE_700F	0x700F
 #define PCI_DEVICE_ID_AMD_COBRA_7400	0x7400
diff -urN linux-2.4.21-pre1/include/linux/raid/md_k.h linux-2.4.21-pre2/include/linux/raid/md_k.h
--- linux-2.4.21-pre1/include/linux/raid/md_k.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/linux/raid/md_k.h	Wed Dec 18 14:16:28 2002
@@ -171,6 +171,7 @@
 	struct block_device *bdev;	/* block device handle */
 
 	mdp_super_t *sb;
+	struct page *sb_page;
 	unsigned long sb_offset;
 
 	int alias_device;		/* device alias to the same disk */
diff -urN linux-2.4.21-pre1/include/linux/sysctl.h linux-2.4.21-pre2/include/linux/sysctl.h
--- linux-2.4.21-pre1/include/linux/sysctl.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/linux/sysctl.h	Wed Dec 18 14:16:28 2002
@@ -124,6 +124,7 @@
 	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
+ 	KERN_CORE_PATTERN=56,	/* string: pattern for core-files */
 };
 
 
diff -urN linux-2.4.21-pre1/include/linux/videodev.h linux-2.4.21-pre2/include/linux/videodev.h
--- linux-2.4.21-pre1/include/linux/videodev.h	Wed Dec 18 14:16:25 2002
+++ linux-2.4.21-pre2/include/linux/videodev.h	Wed Dec 18 14:16:28 2002
@@ -404,6 +404,7 @@
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2	33
 #define VID_HARDWARE_VICAM	34	/* ViCam, 3Com Homeconnect */
+#define VID_HARDWARE_SF16FMR2	35
 
 #endif /* __LINUX_VIDEODEV_H */
 
diff -urN linux-2.4.21-pre1/include/linux/wireless.h linux-2.4.21-pre2/include/linux/wireless.h
--- linux-2.4.21-pre1/include/linux/wireless.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/linux/wireless.h	Wed Dec 18 14:16:28 2002
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	14	25.1.02
+ * Version :	15	12.7.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
@@ -80,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	14
+#define WIRELESS_EXT	15
 
 /*
  * Changes :
@@ -153,17 +153,32 @@
  *	- Define additional specific event numbers
  *	- Add "addr" and "param" fields in union iwreq_data
  *	- AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *	- Make struct iw_freq signed (both m & e), add explicit padding
+ *	- Add IWEVCUSTOM for driver specific event/scanning token
+ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *	- Add IW_TXPOW_RANGE for range of Tx Powers
+ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *	- Add IW_MODE_MONITOR for passive monitor
  */
 
 /**************************** CONSTANTS ****************************/
 
 /* -------------------------- IOCTL LIST -------------------------- */
 
-/* Basic operations */
+/* Wireless Identification */
 #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
-#define SIOCGIWNWID	0x8B03		/* get network id */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
+#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
@@ -178,16 +193,18 @@
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
 #define SIOCSIWSTATS	0x8B0E		/* Unused */
 #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support */
+/* Mobile IP support (statistics per MAC address) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
 #define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
@@ -197,9 +214,7 @@
 #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
 /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
  * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE...
- * The "flags" member indicate if the ESSID is active or not (promiscuous).
- */
+ * point to a string in user space, like it is done for RANGE... */
 
 /* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
@@ -257,7 +272,10 @@
 /* Most events use the same identifier as ioctl requests */
 
 #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
+#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
 
 #define IWEVFIRST	0x8C00
 
@@ -273,7 +291,8 @@
 #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
 #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
 #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000
+#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
 
 #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
 
@@ -297,13 +316,16 @@
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
+#define IW_MAX_SPY		8	/* set */
+#define IW_MAX_GET_SPY		64	/* get */
 
 /* Maximum of address that you may get in the
    list of access points in range */
-#define IW_MAX_AP		8
+#define IW_MAX_AP		64
 
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE	32
@@ -315,6 +337,7 @@
 #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
 #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
@@ -350,8 +373,10 @@
 #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
 /* Transmit Power flags available */
+#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
 #define IW_RETRY_ON		0x0000	/* No details... */
@@ -376,6 +401,9 @@
 /* Maximum size of returned data */
 #define IW_SCAN_MAX_DATA	4096	/* In bytes */
 
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX		256	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -411,9 +439,10 @@
  */
 struct	iw_freq
 {
-	__u32		m;		/* Mantissa */
-	__u16		e;		/* Exponent */
+	__s32		m;		/* Mantissa */
+	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
+	__u8		pad;		/* Unused - just for alignement */
 };
 
 /*
diff -urN linux-2.4.21-pre1/include/net/irda/irlap.h linux-2.4.21-pre2/include/net/irda/irlap.h
--- linux-2.4.21-pre1/include/net/irda/irlap.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.21-pre2/include/net/irda/irlap.h	Wed Dec 18 14:16:28 2002
@@ -31,8 +31,6 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-comp.h>
 #include <linux/timer.h>
 
 #include <net/irda/irlap_event.h>
@@ -216,4 +214,24 @@
 #define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irlap_is_primary(struct irlap_cb *self)
+{
+	int ret;
+	switch(self->state) {
+	case LAP_XMIT_P:
+	case LAP_NRM_P:
+		ret = 1;
+		break;
+	case LAP_XMIT_S:
+	case LAP_NRM_S:
+		ret = 0;
+		break;
+	default:
+		ret = -1;
+	}
+	return(ret);
+}
+
 #endif
diff -urN linux-2.4.21-pre1/include/net/irda/irlmp.h linux-2.4.21-pre2/include/net/irda/irlmp.h
--- linux-2.4.21-pre1/include/net/irda/irlmp.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/net/irda/irlmp.h	Wed Dec 18 14:16:28 2002
@@ -274,6 +274,8 @@
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	self->lsap_state = LSAP_DISCONNECTED;
+	/* Started when we received the LM_CONNECT_INDICATION */
+	del_timer(&self->watchdog_timer);
 }
 
 #endif
diff -urN linux-2.4.21-pre1/include/net/irda/irttp.h linux-2.4.21-pre2/include/net/irda/irttp.h
--- linux-2.4.21-pre1/include/net/irda/irttp.h	Fri Dec 21 09:42:04 2001
+++ linux-2.4.21-pre2/include/net/irda/irttp.h	Wed Dec 18 14:16:28 2002
@@ -42,11 +42,48 @@
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
-#define DEFAULT_INITIAL_CREDIT 14
+/* Transmission queue sizes */
+/* Worst case scenario, two window of data - Jean II */
+#define TTP_TX_MAX_QUEUE	14
+/* We need to keep at least 5 frames to make sure that we can refill
+ * appropriately the LAP layer. LAP keeps only two buffers, and we need
+ * to have 7 to make a full window - Jean II */
+#define TTP_TX_LOW_THRESHOLD	5
+/* Most clients are synchronous with respect to flow control, so we can
+ * keep a low number of Tx buffers in TTP - Jean II */
+#define TTP_TX_HIGH_THRESHOLD	7
+
+/* Receive queue sizes */
+/* Minimum of credit that the peer should hold.
+ * If the peer has less credits than 9 frames, we will explicitely send
+ * him some credits (through irttp_give_credit() and a specific frame).
+ * Note that when we give credits it's likely that it won't be sent in
+ * this LAP window, but in the next one. So, we make sure that the peer
+ * has something to send while waiting for credits (one LAP window == 7
+ * + 1 frames while he process the credits). - Jean II */
+#define TTP_RX_MIN_CREDIT	8
+/* This is the default maximum number of credits held by the peer, so the
+ * default maximum number of frames he can send us before needing flow
+ * control answer from us (this may be negociated differently at TSAP setup).
+ * We want to minimise the number of times we have to explicitely send some
+ * credit to the peer, hoping we can piggyback it on the return data. In
+ * particular, it doesn't make sense for us to send credit more than once
+ * per LAP window.
+ * Moreover, giving credits has some latency, so we need strictly more than
+ * a LAP window, otherwise we may already have credits in our Tx queue.
+ * But on the other hand, we don't want to keep too many Rx buffer here
+ * before starting to flow control the other end, so make it exactly one
+ * LAP window + 1 + MIN_CREDITS. - Jean II */
+#define TTP_RX_DEFAULT_CREDIT	16
+/* Maximum number of credits we can allow the peer to have, and therefore
+ * maximum Rx queue size.
+ * Note that we try to deliver packets to the higher layer every time we
+ * receive something, so in normal mode the Rx queue will never contains
+ * more than one or two packets. - Jean II */
+#define TTP_RX_MAX_CREDIT	21
 
-#define TTP_LOW_THRESHOLD       4
-#define TTP_HIGH_THRESHOLD     10
-#define TTP_MAX_QUEUE          14
+/* What clients should use when calling ttp_open_tsap() */
+#define DEFAULT_INITIAL_CREDIT	TTP_RX_DEFAULT_CREDIT
 
 /* Some priorities for disconnect requests */
 #define P_NORMAL    0
@@ -90,7 +127,7 @@
 
 	struct net_device_stats stats;
 	struct timer_list todo_timer; 
-	
+
 	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
 	__u8  max_header_size;
 
@@ -131,6 +168,7 @@
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
 void irttp_status_indication(void *instance,
 			     LINK_STATUS link, LOCK_STATUS lock);
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
 
 static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
@@ -159,6 +197,18 @@
 	self->dtsap_sel = LSAP_ANY;
 }
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irttp_is_primary(struct tsap_cb *self)
+{
+	if ((self == NULL) ||
+	    (self->lsap == NULL) ||
+	    (self->lsap->lap == NULL) ||
+	    (self->lsap->lap->irlap == NULL))
+		return -2;
+	return(irlap_is_primary(self->lsap->lap->irlap));
+}
+
 extern struct irttp_cb *irttp;
 
 #endif /* IRTTP_H */
diff -urN linux-2.4.21-pre1/include/net/iw_handler.h linux-2.4.21-pre2/include/net/iw_handler.h
--- linux-2.4.21-pre1/include/net/iw_handler.h	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/include/net/iw_handler.h	Wed Dec 18 14:16:28 2002
@@ -1,7 +1,7 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	3	17.1.02
+ * Version :	4	21.6.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	3
+#define IW_HANDLER_VERSION	4
 
 /*
  * Changes :
@@ -217,6 +217,9 @@
  *	- Add Wireless Event support :
  *		o wireless_send_event() prototype
  *		o iwe_stream_add_event/point() inline functions
+ * V3 to V4
+ * --------
+ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
  */
 
 /**************************** CONSTANTS ****************************/
@@ -233,10 +236,10 @@
 #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
 #define IW_HEADER_TYPE_UINT	4	/* __u32 */
 #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
diff -urN linux-2.4.21-pre1/include/pcmcia/ciscode.h linux-2.4.21-pre2/include/pcmcia/ciscode.h
--- linux-2.4.21-pre1/include/pcmcia/ciscode.h	Fri Dec 21 09:42:04 2001
+++ linux-2.4.21-pre2/include/pcmcia/ciscode.h	Wed Dec 18 14:16:28 2002
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.48 2001/08/24 12:16:12
+ * ciscode.h 1.57 2002/11/03 20:38:14
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -60,6 +60,10 @@
 #define PRODID_INTEL_DUAL_RS232		0x0301
 #define PRODID_INTEL_2PLUS		0x8422
 
+#define MANFID_KME			0x0032
+#define PRODID_KME_KXLC005_A		0x0704
+#define PRODID_KME_KXLC005_B		0x2904
+
 #define MANFID_LINKSYS			0x0143
 #define PRODID_LINKSYS_PCMLM28		0xc0ab
 #define PRODID_LINKSYS_3400		0x3341
@@ -94,6 +98,8 @@
 #define PRODID_OSITECH_JACK_336		0x0007
 #define PRODID_OSITECH_SEVEN		0x0008
 
+#define MANFID_OXSEMI			0x0279
+
 #define MANFID_PIONEER			0x000b
 
 #define MANFID_PSION			0x016c
@@ -103,6 +109,7 @@
 #define PRODID_QUATECH_SPP100		0x0003
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
+#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
 #define PRODID_QUATECH_QUAD_RS232	0x001b
 #define PRODID_QUATECH_DUAL_RS422	0x000e
 #define PRODID_QUATECH_QUAD_RS422	0x0045
@@ -120,9 +127,12 @@
 
 #define MANFID_TDK			0x0105
 #define PRODID_TDK_CF010		0x0900
+#define PRODID_TDK_GN3410		0x4815
 
 #define MANFID_TOSHIBA			0x0098
 
+#define MANFID_UNGERMANN		0x02c0
+
 #define MANFID_XIRCOM			0x0105
 
 #endif /* _LINUX_CISCODE_H */
diff -urN linux-2.4.21-pre1/mm/slab.c linux-2.4.21-pre2/mm/slab.c
--- linux-2.4.21-pre1/mm/slab.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/mm/slab.c	Wed Dec 18 14:16:28 2002
@@ -989,6 +989,8 @@
  * cache being allocated each time a module is loaded and unloaded, if the
  * module doesn't have persistent in-kernel storage across loads and unloads.
  *
+ * The cache must be empty before calling this function.
+ *
  * The caller must guarantee that noone will allocate memory from the cache
  * during the kmem_cache_destroy().
  */
diff -urN linux-2.4.21-pre1/net/802/tr.c linux-2.4.21-pre2/net/802/tr.c
--- linux-2.4.21-pre1/net/802/tr.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.21-pre2/net/802/tr.c	Wed Dec 18 14:16:28 2002
@@ -93,10 +93,10 @@
 	int hdr_len;
 
 	/* 
-	 * Add the 802.2 SNAP header if IP as the IPv4 code calls  
+	 * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls  
 	 * dev->hard_header directly.
 	 */
-	if (type == ETH_P_IP || type == ETH_P_ARP)
+	if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
 	{
 		struct trllc *trllc=(struct trllc *)(trh+1);
 
@@ -218,6 +218,7 @@
 
 	if (trllc->dsap == EXTENDED_SAP &&
 	    (trllc->ethertype == ntohs(ETH_P_IP) ||
+	     trllc->ethertype == ntohs(ETH_P_IPV6) ||
 	     trllc->ethertype == ntohs(ETH_P_ARP)))
 	{
 		skb_pull(skb, sizeof(struct trllc));
diff -urN linux-2.4.21-pre1/net/core/wireless.c linux-2.4.21-pre2/net/core/wireless.c
--- linux-2.4.21-pre1/net/core/wireless.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/net/core/wireless.c	Wed Dec 18 14:16:28 2002
@@ -33,8 +33,16 @@
  *	o Propagate events as rtnetlink IFLA_WIRELESS option
  *	o Generate event on selected SET requests
  *
- * v4 - 18.04.01 - Jean II
+ * v4 - 18.04.02 - Jean II
  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
  */
 
 /***************************** INCLUDES *****************************/
@@ -50,8 +58,9 @@
 
 /**************************** CONSTANTS ****************************/
 
-/* This will be turned on later on... */
-#undef WE_STRICT_WRITE		/* Check write buffer size */
+/* Enough lenience, let's make sure things are proper... */
+#define WE_STRICT_WRITE		/* Check write buffer size */
+/* I'll probably drop both the define and kernel message in the next version */
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
@@ -106,7 +115,7 @@
 	/* SIOCSIWSPY */
 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
 	/* SIOCGIWSPY */
-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -176,25 +185,41 @@
 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 	/* IWEVQUAL */
 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+	/* IWEVCUSTOM */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
+	/* IWEVREGISTERED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVEXPIRED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 };
 static const int standard_event_num = (sizeof(standard_event) /
 				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
-	IW_EV_LCP_LEN,
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
 	0,
-	IW_EV_CHAR_LEN,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
 	0,
-	IW_EV_UINT_LEN,
-	IW_EV_FREQ_LEN,
 	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,
-	IW_EV_ADDR_LEN,
-	IW_EV_QUAL_LEN,
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
 };
 
 /************************ COMMON SUBROUTINES ************************/
@@ -440,8 +465,10 @@
 		return -EFAULT;
 #ifdef WE_STRICT_WRITE
 	/* Check if there is enough buffer up there */
-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
 		return -E2BIG;
+	}
 #endif	/* WE_STRICT_WRITE */
 
 	/* Set the number of available ioctls. */
@@ -471,6 +498,7 @@
 	const struct iw_ioctl_description *	descr;
 	struct iw_request_info			info;
 	int					ret = -EINVAL;
+	int					user_size = 0;
 
 	/* Get the description of the IOCTL */
 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -518,11 +546,8 @@
 			/* Check NULL pointer */
 			if(iwr->u.data.pointer == NULL)
 				return -EFAULT;
-#ifdef WE_STRICT_WRITE
-			/* Check if there is enough buffer up there */
-			if(iwr->u.data.length < descr->max_tokens)
-				return -E2BIG;
-#endif	/* WE_STRICT_WRITE */
+			/* Save user space buffer size for checking */
+			user_size = iwr->u.data.length;
 		}
 
 #ifdef WE_IOCTL_DEBUG
@@ -559,6 +584,15 @@
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(user_size < iwr->u.data.length) {
+				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+				kfree(extra);
+				return -E2BIG;
+			}
+#endif	/* WE_STRICT_WRITE */
+
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   iwr->u.data.length *
 					   descr->token_size);
@@ -646,12 +680,18 @@
 	/* Compute the size of the set/get arguments */
 	if(descr != NULL) {
 		if(IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if(descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
 			/* Size of set arguments */
 			extra_size = get_priv_size(descr->set_args);
 
 			/* Does it fits in iwr ? */
 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   ((extra_size + offset) <= IFNAMSIZ))
 				extra_size = 0;
 		} else {
 			/* Size of set arguments */
@@ -659,7 +699,7 @@
 
 			/* Does it fits in iwr ? */
 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   (extra_size <= IFNAMSIZ))
 				extra_size = 0;
 		}
 	}
@@ -925,7 +965,7 @@
 		 * The best the driver could do is to log an error message.
 		 * We will do it ourselves instead...
 		 */
-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
 		       dev->name, cmd);
 		return;
 	}
diff -urN linux-2.4.21-pre1/net/ipv4/netfilter/ip_tables.c linux-2.4.21-pre2/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.21-pre1/net/ipv4/netfilter/ip_tables.c	Thu Nov 28 15:53:15 2002
+++ linux-2.4.21-pre2/net/ipv4/netfilter/ip_tables.c	Wed Dec 18 14:16:28 2002
@@ -68,13 +68,12 @@
 #define inline
 #endif
 
-/* Locking is simple: we assume at worst case there will be one packet
-   in user context and one from bottom halves (or soft irq if Alexey's
-   softnet patch was applied).
-
+/*
    We keep a set of rules for each CPU, so we can avoid write-locking
-   them; doing a readlock_bh() stops packets coming through if we're
-   in user context.
+   them in the softirq when updating the counters and therefore
+   only need to read-lock in the softirq; doing a write_lock_bh() in user
+   context stops packets coming through and allows user context to read
+   the counters or update the rules.
 
    To be cache friendly on SMP, we arrange them like so:
    [ n-entries ]
diff -urN linux-2.4.21-pre1/net/irda/ircomm/ircomm_core.c linux-2.4.21-pre2/net/irda/ircomm/ircomm_core.c
--- linux-2.4.21-pre1/net/irda/ircomm/ircomm_core.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.21-pre2/net/irda/ircomm/ircomm_core.c	Wed Dec 18 14:16:28 2002
@@ -498,7 +498,7 @@
 
 	self = (struct ircomm_cb *) hashbin_get_first(ircomm);
 	while (self != NULL) {
-		ASSERT(self->magic == IRCOMM_MAGIC, return len;);
+		ASSERT(self->magic == IRCOMM_MAGIC, break;);
 
 		if(self->line < 0x10)
 			len += sprintf(buf+len, "ircomm%d", self->line);
diff -urN linux-2.4.21-pre1/net/irda/ircomm/ircomm_tty.c linux-2.4.21-pre2/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.21-pre1/net/irda/ircomm/ircomm_tty.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/ircomm/ircomm_tty.c	Wed Dec 18 14:16:28 2002
@@ -512,6 +512,9 @@
 	if (!tty)
 		return;
 
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
 	save_flags(flags); 
 	cli();
 
@@ -523,9 +526,6 @@
 		return;
 	}
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
 	if ((tty->count == 1) && (self->open_count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
diff -urN linux-2.4.21-pre1/net/irda/irda_device.c linux-2.4.21-pre2/net/irda/irda_device.c
--- linux-2.4.21-pre1/net/irda/irda_device.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.21-pre2/net/irda/irda_device.c	Wed Dec 18 14:16:28 2002
@@ -369,6 +369,12 @@
  *    time to complete. We do it this hairy way since we may have been
  *    called from interrupt context, so it's not possible to use
  *    schedule_timeout() 
+ * Two important notes :
+ *	o Make sure you irda_task_delete(task); in case you delete the
+ *	  calling instance.
+ *	o No real need to lock when calling this function, but you may
+ *	  want to lock within the task handler.
+ * Jean II
  */
 struct irda_task *irda_task_execute(void *instance, 
 				    IRDA_TASK_CALLBACK function, 
@@ -467,6 +473,9 @@
  * Function irda_device_init_dongle (self, type, qos)
  *
  *    Initialize attached dongle.
+ *
+ * Important : request_module require us to call this function with
+ * a process context and irq enabled. - Jean II
  */
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
 {
@@ -478,6 +487,7 @@
 #ifdef CONFIG_KMOD
 	{
 	char modname[32];
+	ASSERT(!in_interrupt(), return NULL;);
 	/* Try to load the module needed */
 	sprintf(modname, "irda-dongle-%d", type);
 	request_module(modname);
diff -urN linux-2.4.21-pre1/net/irda/irlap.c linux-2.4.21-pre2/net/irda/irlap.c
--- linux-2.4.21-pre1/net/irda/irlap.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/irlap.c	Wed Dec 18 14:16:28 2002
@@ -1101,8 +1101,8 @@
 
 	self = (struct irlap_cb *) hashbin_get_first(irlap);
 	while (self != NULL) {
-		ASSERT(self != NULL, return -ENODEV;);
-		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+		ASSERT(self != NULL, break;);
+		ASSERT(self->magic == LAP_MAGIC, break;);
 
 		len += sprintf(buf+len, "irlap%d ", i++);
 		len += sprintf(buf+len, "state: %s\n", 
diff -urN linux-2.4.21-pre1/net/irda/irlmp.c linux-2.4.21-pre2/net/irda/irlmp.c
--- linux-2.4.21-pre1/net/irda/irlmp.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/irlmp.c	Wed Dec 18 14:16:28 2002
@@ -236,6 +236,16 @@
 	lap = self->lap;
 	if (lap) {
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		/* We might close a LSAP before it has completed the
+		 * connection setup. In those case, higher layers won't
+		 * send a proper disconnect request. Harmless, except
+		 * that we will forget to close LAP... - Jean II */
+		if(self->lsap_state != LSAP_DISCONNECTED) {
+			self->lsap_state = LSAP_DISCONNECTED;
+			irlmp_do_lap_event(self->lap,
+					   LM_LAP_DISCONNECT_REQUEST, NULL);
+		}
+		/* Now, remove from the link */
 		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
 	}
 	self->lap = NULL;
@@ -1674,7 +1684,7 @@
 	len += sprintf( buf+len, "Unconnected LSAPs:\n");
 	self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps);
 	while (self != NULL) {
-		ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+		ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 		len += sprintf(buf+len, "lsap state: %s, ", 
 			       irlsap_state[ self->lsap_state]);
 		len += sprintf(buf+len, 
@@ -1703,7 +1713,7 @@
 		len += sprintf(buf+len, "\n  Connected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+			ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 			len += sprintf(buf+len, "  lsap state: %s, ", 
 				       irlsap_state[ self->lsap_state]);
 			len += sprintf(buf+len, 
diff -urN linux-2.4.21-pre1/net/irda/irlmp_event.c linux-2.4.21-pre2/net/irda/irlmp_event.c
--- linux-2.4.21-pre1/net/irda/irlmp_event.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/irlmp_event.c	Wed Dec 18 14:16:28 2002
@@ -414,7 +414,7 @@
 
 			/* We don't want to change state just yet, because
 			 * we want to reflect accurately the real state of
-			 * the LAP, not the the state we whish it was in,
+			 * the LAP, not the state we wish it was in,
 			 * so that we don't loose LM_LAP_CONNECT_REQUEST.
 			 * In some cases, IrLAP won't close the LAP
 			 * immediately. For example, it might still be
diff -urN linux-2.4.21-pre1/net/irda/irnet/irnet.h linux-2.4.21-pre2/net/irda/irnet/irnet.h
--- linux-2.4.21-pre1/net/irda/irnet/irnet.h	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/irnet/irnet.h	Wed Dec 18 14:16:28 2002
@@ -217,6 +217,11 @@
  *	  Better fix in irnet_disconnect_indication() :
  *	  - if connected, kill pppd via hangup.
  *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
+ *
+ * v12 - 10.4.02 - Jean II
+ *	o Fix race condition in irnet_connect_indication().
+ *	  If the socket was already trying to connect, drop old connection
+ *	  and use new one only if acting as primary. See comments.
  */
 
 /***************************** INCLUDES *****************************/
diff -urN linux-2.4.21-pre1/net/irda/irnet/irnet_irda.c linux-2.4.21-pre2/net/irda/irnet/irnet_irda.c
--- linux-2.4.21-pre1/net/irda/irnet/irnet_irda.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/irda/irnet/irnet_irda.c	Wed Dec 18 14:16:28 2002
@@ -1340,46 +1340,80 @@
       return;
     }
 
-  /* Socket connecting ?
-   * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */
-  if(test_and_clear_bit(0, &new->ttp_connect))
-    {
-      /* The socket is trying to connect to the other end and may have sent
-       * a IrTTP connection request and is waiting for a connection response
-       * (that may never come).
-       * Now, the pain is that the socket may have opened a tsap and is
-       * waiting on it, while the other end is trying to connect to it on
-       * another tsap.
-       */
-      DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
+  /* The following code is a bit tricky, so need comments ;-)
+   */
+  /* If ttp_connect is set, the socket is trying to connect to the other
+   * end and may have sent a IrTTP connection request and is waiting for
+   * a connection response (that may never come).
+   * Now, the pain is that the socket may have opened a tsap and is
+   * waiting on it, while the other end is trying to connect to it on
+   * another tsap.
+   * Because IrNET can be peer to peer, we need to workaround this.
+   * Furthermore, the way the irnetd script is implemented, the
+   * target will create a second IrNET connection back to the
+   * originator and expect the originator to bind this new connection
+   * to the original PPPD instance.
+   * And of course, if we don't use irnetd, we can have a race when
+   * both side try to connect simultaneously, which could leave both
+   * connections half closed (yuck).
+   * Conclusions :
+   *	1) The "originator" must accept the new connection and get rid
+   *	   of the old one so that irnetd works
+   *	2) One side must deny the new connection to avoid races,
+   *	   but both side must agree on which side it is...
+   * Most often, the originator is primary at the LAP layer.
+   * Jean II
+   */
+  /* Now, let's look at the way I wrote the test...
+   * We need to clear up the ttp_connect flag atomically to prevent
+   * irnet_disconnect_indication() to mess up the tsap we are going to close.
+   * We want to clear the ttp_connect flag only if we close the tsap,
+   * otherwise we will never close it, so we need to check for primary
+   * *before* doing the test on the flag.
+   * And of course, ALLOW_SIMULT_CONNECT can disable this entirely...
+   * Jean II
+   */
+
+  /* Socket already connecting ? On primary ? */
+  if(0
 #ifdef ALLOW_SIMULT_CONNECT
-      /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */
+     || ((irttp_is_primary(server->tsap) == 1)	/* primary */
+	 && (test_and_clear_bit(0, &new->ttp_connect)))
+#endif /* ALLOW_SIMULT_CONNECT */
+     )
+    {
+      DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");
+
+      /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */
       if(new->tsap != NULL)
 	{
-	  /* Close the connection the new socket was attempting.
-	   * This seems to be safe... */
+	  /* Close the old connection the new socket was attempting,
+	   * so that we can hook it up to the new connection.
+	   * It's now safe to do it... */
 	  irttp_close_tsap(new->tsap);
 	  new->tsap = NULL;
 	}
-      /* Note : no return, fall through... */
-#else /* ALLOW_SIMULT_CONNECT */
-      irnet_disconnect_server(server, skb);
-      return;
-#endif /* ALLOW_SIMULT_CONNECT */
     }
   else
-    /* If socket is not connecting or connected, tsap should be NULL */
-    if(new->tsap != NULL)
-      {
-	/* If we are here, we are also in irnet_disconnect_indication(),
-	 * and it's a nice race condition... On the other hand, we can't be
-	 * in irda_irnet_destroy() otherwise we would not have found the
-	 * socket in the hashbin. */
-	/* Better get out of here, otherwise we will mess up tsaps ! */
-	DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n");
-	irnet_disconnect_server(server, skb);
-	return;
-      }
+    {
+      /* Three options :
+       * 1) socket was not connecting or connected : ttp_connect should be 0.
+       * 2) we don't want to connect the socket because we are secondary or
+       * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.
+       * 3) we are half way in irnet_disconnect_indication(), and it's a
+       * nice race condition... Fortunately, we can detect that by checking
+       * if tsap is still alive. On the other hand, we can't be in
+       * irda_irnet_destroy() otherwise we would not have found this
+       * socket in the hashbin.
+       * Jean II */
+      if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))
+	{
+	  /* Don't mess this socket, somebody else in in charge... */
+	  DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");
+	  irnet_disconnect_server(server, skb);
+	  return;
+	}
+    }
 
   /* So : at this point, we have a socket, and it is idle. Good ! */
   irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
diff -urN linux-2.4.21-pre1/net/irda/irttp.c linux-2.4.21-pre2/net/irda/irttp.c
--- linux-2.4.21-pre1/net/irda/irttp.c	Fri Nov  9 14:22:17 2001
+++ linux-2.4.21-pre2/net/irda/irttp.c	Wed Dec 18 14:16:28 2002
@@ -59,8 +59,8 @@
 
 static void irttp_flush_queues(struct tsap_cb *self);
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static void irttp_todo_expired(unsigned long data);
 static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
 				    int get);
 
@@ -72,6 +72,8 @@
 static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
 static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
+/************************ GLOBAL PROCEDURES ************************/
+
 /*
  * Function irttp_init (void)
  *
@@ -126,6 +128,239 @@
 }
 #endif
 
+/*************************** SUBROUTINES ***************************/
+
+/*
+ * Function irttp_start_todo_timer (self, timeout)
+ *
+ *    Start todo timer. 
+ *
+ * Made it more effient and unsensitive to race conditions - Jean II
+ */
+static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
+{
+	/* Set new value for timer */
+	mod_timer(&self->todo_timer, jiffies + timeout);
+}
+
+/*
+ * Function irttp_todo_expired (data)
+ *
+ *    Todo timer has expired!
+ *
+ * One of the restriction of the timer is that it is run only on the timer
+ * interrupt which run every 10ms. This mean that even if you set the timer
+ * with a delay of 0, it may take up to 10ms before it's run.
+ * So, to minimise latency and keep cache fresh, we try to avoid using
+ * it as much as possible.
+ * Note : we can't use tasklets, because they can't be asynchronously
+ * killed (need user context), and we can't guarantee that here...
+ * Jean II
+ */
+static void irttp_todo_expired(unsigned long data)
+{
+	struct tsap_cb *self = (struct tsap_cb *) data;
+
+	/* Check that we still exist */
+	if (!self || self->magic != TTP_TSAP_MAGIC)
+		return;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* Try to make some progress, especially on Tx side - Jean II */
+	irttp_run_rx_queue(self);
+	irttp_run_tx_queue(self);
+
+	/* Check if time for disconnect */
+	if (test_bit(0, &self->disconnect_pend)) {
+		/* Check if it's possible to disconnect yet */
+		if (skb_queue_empty(&self->tx_queue)) {
+			/* Make sure disconnect is not pending anymore */
+			clear_bit(0, &self->disconnect_pend);	/* FALSE */
+
+			/* Note : self->disconnect_skb may be NULL */
+			irttp_disconnect_request(self, self->disconnect_skb,
+						 P_NORMAL);
+			self->disconnect_skb = NULL;
+		} else {
+			/* Try again later */
+			irttp_start_todo_timer(self, HZ/10);
+			
+			/* No reason to try and close now */
+			return;
+		}
+	}
+	
+	/* Check if it's closing time */
+	if (self->close_pend)
+		/* Finish cleanup */
+		irttp_close_tsap(self);
+}
+
+/*
+ * Function irttp_flush_queues (self)
+ *
+ *     Flushes (removes all frames) in transitt-buffer (tx_list)
+ */
+void irttp_flush_queues(struct tsap_cb *self)
+{
+	struct sk_buff* skb;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	/* Deallocate frames waiting to be sent */
+	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received frames */
+	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received fragments */
+	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
+		dev_kfree_skb(skb);
+}
+
+/*
+ * Function irttp_reassemble (self)
+ *
+ *    Makes a new (continuous) skb of all the fragments in the fragment
+ *    queue
+ *
+ */
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
+{
+	struct sk_buff *skb, *frag;
+	int n = 0;  /* Fragment index */
+	
+      	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
+
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
+	if (!skb)
+		return NULL;
+
+	/* 
+	 * Need to reserve space for TTP header in case this skb needs to 
+	 * be requeued in case delivery failes
+	 */
+	skb_reserve(skb, TTP_HEADER);
+	skb_put(skb, self->rx_sdu_size);
+
+	/*
+	 *  Copy all fragments to a new buffer
+	 */
+	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
+		memcpy(skb->data+n, frag->data, frag->len);
+		n += frag->len;
+		
+		dev_kfree_skb(frag);
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
+	skb_trim(skb, n);
+
+	self->rx_sdu_size = 0;
+
+	return skb;
+}
+
+/*
+ * Function irttp_fragment_skb (skb)
+ *
+ *    Fragments a frame and queues all the fragments for transmission
+ *
+ */
+static inline void irttp_fragment_skb(struct tsap_cb *self,
+				      struct sk_buff *skb)
+{
+	struct sk_buff *frag;
+	__u8 *frame;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+
+	/*
+	 *  Split frame into a number of segments
+	 */
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
+		/* Make new segment */
+		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
+		if (!frag)
+			return;
+
+		skb_reserve(frag, self->max_header_size);
+
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
+		frame[0] = TTP_MORE;
+		
+		/* Hide the copied data from the original skb */
+		skb_pull(skb, self->max_seg_size);
+
+		/* Queue fragment */
+		skb_queue_tail(&self->tx_queue, frag);
+	}
+	/* Queue what is left of the original skb */
+	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
+	
+	frame = skb_push(skb, TTP_HEADER);
+	frame[0] = 0x00; /* Clear more bit */
+
+	/* Queue fragment */
+	skb_queue_tail(&self->tx_queue, skb);
+}
+
+/*
+ * Function irttp_param_max_sdu_size (self, param)
+ *
+ *    Handle the MaxSduSize parameter in the connect frames, this function
+ *    will be called both when this parameter needs to be inserted into, and
+ *    extracted from the connect frames
+ */
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
+				    int get)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->tx_max_sdu_size;
+	else
+		self->tx_max_sdu_size = param->pv.i;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
+}
+
+/*************************** CLIENT CALLS ***************************/
+/************************** LMP CALLBACKS **************************/
+/* Everything is happily mixed up. Waiting for next clean up - Jean II */
+
 /*
  * Function irttp_open_tsap (stsap, notify)
  *
@@ -157,7 +392,10 @@
 	memset(self, 0, sizeof(struct tsap_cb));
 	spin_lock_init(&self->lock);
 
+	/* Initialise todo timer */
 	init_timer(&self->todo_timer);
+	self->todo_timer.data     = (unsigned long) self;
+	self->todo_timer.function = &irttp_todo_expired;
 
 	/* Initialize callbacks for IrLMP to use */
 	irda_notify_init(&ttp_notify);
@@ -166,6 +404,7 @@
 	ttp_notify.disconnect_indication = irttp_disconnect_indication;
 	ttp_notify.data_indication = irttp_data_indication;
 	ttp_notify.udata_indication = irttp_udata_indication;
+	ttp_notify.flow_indication = irttp_flow_indication;
 	if(notify->status_indication != NULL)
 		ttp_notify.status_indication = irttp_status_indication;
 	ttp_notify.instance = self;
@@ -199,8 +438,8 @@
 
 	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
 
-	if (credit > TTP_MAX_QUEUE)
-		self->initial_credit = TTP_MAX_QUEUE;
+	if (credit > TTP_RX_MAX_CREDIT)
+		self->initial_credit = TTP_RX_MAX_CREDIT;
 	else
 		self->initial_credit = credit;
 
@@ -224,7 +463,7 @@
 
 	del_timer(&self->todo_timer);
 
-	/* This one won't be cleaned up if we are diconnect_pend + close_pend
+	/* This one won't be cleaned up if we are disconnect_pend + close_pend
 	 * and we receive a disconnect_indication */
 	if (self->disconnect_skb)
 		dev_kfree_skb(self->disconnect_skb);
@@ -262,7 +501,7 @@
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 1*HZ);
+		irttp_start_todo_timer(self, HZ/10);
 
 		return 0; /* Will be back! */
 	}
@@ -327,6 +566,9 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ " : queue len = %d\n",
+		   skb_queue_len(&self->tx_queue));
+
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
 		WARNING(__FUNCTION__ "(), No data, or not connected\n");
@@ -358,12 +600,14 @@
 	/* 
 	 *  Check if transmit queue is full
 	 */
-	if (skb_queue_len(&self->tx_queue) >= TTP_MAX_QUEUE) {
+	if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {
 		/*
 		 *  Give it a chance to empty itself
 		 */
 		irttp_run_tx_queue(self);
-		
+
+		/* Drop packet. This error code should trigger the caller
+		 * to requeue the packet in the client code - Jean II */
 		return -ENOBUFS;
 	}
        
@@ -387,20 +631,25 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
-		
-		/* Tx queue filling up, so stop client */
-		self->tx_sdu_busy = TRUE;
-		
-	 	if (self->notify.flow_indication) {
+	    (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {
+		/* Tx queue filling up, so stop client. */
+		if (self->notify.flow_indication) {
  			self->notify.flow_indication(self->notify.instance, 
 						     self, FLOW_STOP);
 		}
- 	}
+		/* self->tx_sdu_busy is the state of the client.
+		 * Update state after notifying client to avoid
+		 * race condition with irttp_flow_indication().
+		 * If the queue empty itself after our test but before
+		 * we set the flag, we will fix ourselves below in
+		 * irttp_run_tx_queue().
+		 * Jean II */
+		self->tx_sdu_busy = TRUE;
+	}
 	
 	/* Try to make some progress */
 	irttp_run_tx_queue(self);
-	
+
 	return 0;
 }
 
@@ -416,28 +665,20 @@
 	unsigned long flags;
 	int n;
 
+	IRDA_DEBUG(2, __FUNCTION__ "() : send_credit = %d, queue_len = %d\n",
+		   self->send_credit, skb_queue_len(&self->tx_queue));
+
 	/* Get exclusive access to the tx queue, otherwise don't touch it */
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	/* Try to send out frames as long as we have credits */
+	/* Try to send out frames as long as we have credits
+	 * and as long as LAP is not full. If LAP is full, it will
+	 * poll us through irttp_flow_indication() - Jean II */
 	while ((self->send_credit > 0) &&
+	       (!irlmp_lap_tx_queue_full(self->lsap)) &&
 	       (skb = skb_dequeue(&self->tx_queue)))
 	{
-		/* 
-		 * Make sure we don't flood IrLAP with frames just because
-		 * the remote device has given us a lot of credits
-		 */
-		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
-			/* Re-queue packet */
-			skb_queue_head(&self->tx_queue, skb);
-
-			/* Try later. Would be better if IrLAP could notify us */
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
-			
-			break;
-		}
-
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -484,32 +725,35 @@
 		 * Jean II */
 		if (skb->sk != NULL) {
 			/* IrSOCK application, IrOBEX, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
-
-			/* That's the right way to do it - Jean II */
 			skb_orphan(skb);
-		} else {
-			/* IrCOMM over IrTTP, IrLAN, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
 		}
+			/* IrCOMM over IrTTP, IrLAN, ... */
 
 		/* Pass the skb to IrLMP - done */
 		irlmp_data_request(self->lsap, skb);
 		self->stats.tx_packets++;
+	}
 
-		/* Check if we can accept more frames from client */
-		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
-		{
-			self->tx_sdu_busy = FALSE;
-			
-			if (self->notify.flow_indication)
-				self->notify.flow_indication(
-					self->notify.instance, self,
-					FLOW_START);
-		}
+	/* Check if we can accept more frames from client.
+	 * We don't want to wait until the todo timer to do that, and we
+	 * can't use tasklets (grr...), so we are obliged to give control
+	 * to client. That's ok, this test will be true not too often
+	 * (max once per LAP window) and we are called from places
+	 * where we can spend a bit of time doing stuff. - Jean II */
+	if ((self->tx_sdu_busy) && 
+	    (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
+	    (!self->close_pend))
+	{
+		if (self->notify.flow_indication)
+			self->notify.flow_indication(self->notify.instance,
+						     self, FLOW_START);
+
+		/* self->tx_sdu_busy is the state of the client.
+		 * We don't really have a race here, but it's always safer
+		 * to update our state after the client - Jean II */
+		self->tx_sdu_busy = FALSE;
 	}
-	
+
 	/* Reset lock */
 	self->tx_queue_lock = 0;
 }
@@ -520,7 +764,7 @@
  *    Send a dataless flowdata TTP-PDU and give available credit to peer
  *    TSAP
  */
-void irttp_give_credit(struct tsap_cb *self) 
+static inline void irttp_give_credit(struct tsap_cb *self) 
 {
 	struct sk_buff *tx_skb = NULL;
 	unsigned long flags;
@@ -531,7 +775,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 		   self->send_credit, self->avail_credit, self->remote_credit);
-	
+
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -606,6 +850,7 @@
 				 struct sk_buff *skb)
 {
 	struct tsap_cb *self;
+	unsigned long flags;
 	int n;
 
 	self = (struct tsap_cb *) instance;
@@ -614,47 +859,66 @@
 
 	self->stats.rx_packets++;
 
+	/*  Deal with inbound credit
+	 *  Since we can transmit and receive frames concurrently, 
+	 *  the code below is a critical region and we must assure that
+	 *  nobody messes with the credits while we update them.
+	 */
+	spin_lock_irqsave(&self->lock, flags);
+	self->send_credit += n;
+	if (skb->len > 1)
+		self->remote_credit--;
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	/* 
 	 *  Data or dataless packet? Dataless frames contains only the 
 	 *  TTP_HEADER. 
 	 */
 	if (skb->len > 1) {
-		/* Deal with inbound credit */
-		self->send_credit += n;
-		self->remote_credit--;
-		
 		/* 
 		 *  We don't remove the TTP header, since we must preserve the
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
 	} else {
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		/* Dataless flowdata TTP-PDU */
 		dev_kfree_skb(skb);
 	}
 
+
+	/* Push data to the higher layer.
+	 * We do it synchronously because running the todo timer for each
+	 * receive packet would be too much overhead and latency.
+	 * By passing control to the higher layer, we run the risk that
+	 * it may take time or grab a lock. Most often, the higher layer
+	 * will only put packet in a queue.
+	 * Anyway, packets are only dripping through the IrDA, so we can
+	 * have time before the next packet.
+	 * Further, we are run from NET_BH, so the worse that can happen is
+	 * us missing the optimal time to send back the PF bit in LAP.
+	 * Jean II */
 	irttp_run_rx_queue(self);
 
-	/* 
-	 *  Give avay some credits to peer? 
-	 */
-	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0)) 
-	{
-		/* Schedule to start immediately after this thread */
-		irttp_start_todo_timer(self, 0);
-		/*irttp_give_credit(self);*/
-	}
-	
+	/* We now give credits to peer in irttp_run_rx_queue().
+	 * We need to send credit *NOW*, otherwise we are going
+	 * to miss the next Tx window. The todo timer may take
+	 * a while before it's run... - Jean II */
+
 	/* 
 	 * If the peer device has given us some credits and we didn't have
-         * anyone from before, the we need to shedule the tx queue?  
+         * anyone from before, then we need to shedule the tx queue.
+	 * We need to do that because our Tx have stopped (so we may not
+	 * get any LAP flow indication) and the user may be stopped as
+	 * well. - Jean II
 	 */
 	if (self->send_credit == n) {
-		/*irttp_run_tx_queue(self);*/
-		irttp_start_todo_timer(self, 0);
+		/* Restart pushing stuff to LAP */
+		irttp_run_tx_queue(self);
+		/* Note : we don't want to schedule the todo timer
+		 * because it has horrible latency. No tasklets
+		 * because the tasklet API is broken. - Jean II */
 	}
+
 	return 0;
 }
 
@@ -687,6 +951,50 @@
 }
 
 /*
+ * Function irttp_flow_indication (self, reason)
+ *
+ *    Flow_indication : IrLAP tells us to send more data.
+ *
+ */
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+	
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* We are "polled" directly from LAP, and the LAP want to fill
+	 * its Tx window. We want to do our best to send it data, so that
+	 * we maximise the window. On the other hand, we want to limit the
+	 * amount of work here so that LAP doesn't hang forever waiting
+	 * for packets. - Jean II */
+
+	/* Try to send some packets. Currently, LAP calls us every time
+	 * there is one free slot, so we will send only one packet.
+	 * This allow the scheduler to do its round robin - Jean II */
+	irttp_run_tx_queue(self);
+
+	/* Note regarding the interraction with higher layer.
+	 * irttp_run_tx_queue() may call the client when its queue
+	 * start to empty, via notify.flow_indication(). Initially.
+	 * I wanted this to happen in a tasklet, to avoid client
+	 * grabbing the CPU, but we can't use tasklets safely. And timer
+	 * is definitely too slow.
+	 * This will happen only once per LAP window, and usually at
+	 * the third packet (unless window is smaller). LAP is still
+	 * doing mtt and sending first packet so it's sort of OK
+	 * to do that. Jean II */
+
+	/* If we need to send disconnect. try to do it now */
+	if(self->disconnect_pend)
+		irttp_start_todo_timer(self, 0);
+}
+
+/*
  * Function irttp_flow_request (self, command)
  *
  *    This funtion could be used by the upper layers to tell IrTTP to stop
@@ -709,7 +1017,10 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
+		/* Client say he can accept more data, try to free our
+		 * queues ASAP - Jean II */
 		irttp_run_rx_queue(self);
+
 		break;
 	default:
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
@@ -1147,10 +1458,15 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			irttp_start_todo_timer(self, HZ/10);
 			return -1;
 		}
 	}
+	/* Note : we don't need to check if self->rx_queue is full and the
+	 * state of self->rx_sdu_busy because the disconnect response will
+	 * be sent at the LMP level (so even if the peer has its Tx queue
+	 * full of data). - Jean II */
+
 	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 	self->connected = FALSE;
 
@@ -1281,8 +1597,7 @@
 	 *  Reassemble all frames in receive queue and deliver them
 	 */
 	while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
-		self->avail_credit++;
-
+		/* This bit will tell us if it's the last fragment or not */
 		more = skb->data[0] & 0x80;
 
 		/* Remove TTP header */
@@ -1293,7 +1608,7 @@
 
 		/*  
 		 * If SAR is disabled, or user has requested no reassembly
-		 * of received fragements then we just deliver them
+		 * of received fragments then we just deliver them
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
@@ -1353,236 +1668,46 @@
 		}
 		self->rx_sdu_size = 0;
 	}
-	/* Reset lock */
-	self->rx_queue_lock = 0;
-}
-
-/*
- * Function irttp_flush_queues (self)
- *
- *     Flushes (removes all frames) in transitt-buffer (tx_list)
- */
-void irttp_flush_queues(struct tsap_cb *self)
-{
-	struct sk_buff* skb;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	
-	/* Deallocate frames waiting to be sent */
-	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received frames */
-	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received fragments */
-	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
-		dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_reasseble (self)
- *
- *    Makes a new (continuous) skb of all the fragments in the fragment
- *    queue
- *
- */
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
-{
-	struct sk_buff *skb, *frag;
-	int n = 0;  /* Fragment index */
-	
-      	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-		   self->rx_sdu_size);
-
-	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
-	if (!skb)
-		return NULL;
-
-	/* 
-	 * Need to reserve space for TTP header in case this skb needs to 
-	 * be requeued in case delivery failes
-	 */
-	skb_reserve(skb, TTP_HEADER);
-	skb_put(skb, self->rx_sdu_size);
 
 	/*
-	 *  Copy all fragments to a new buffer
+	 * It's not trivial to keep track of how many credits are available
+	 * by incrementing at each packet, because delivery may fail 
+	 * (irttp_do_data_indication() may requeue the frame) and because
+	 * we need to take care of fragmentation.
+	 * We want the other side to send up to initial_credit packets.
+	 * We have some frames in our queues, and we have already allowed it
+	 * to send remote_credit.
+	 * No need to spinlock, write is atomic and self correcting...
+	 * Jean II
 	 */
-	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
-		memcpy(skb->data+n, frag->data, frag->len);
-		n += frag->len;
-		
-		dev_kfree_skb(frag);
-	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
-	ASSERT(n <= self->rx_sdu_size, return NULL;);
-
-	/* Set the new length */
-	skb_trim(skb, n);
-
-	self->rx_sdu_size = 0;
-
-	return skb;
-}
-
-/*
- * Function irttp_fragment_skb (skb)
- *
- *    Fragments a frame and queues all the fragments for transmission
- *
- */
-static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
-{
-	struct sk_buff *frag;
-	__u8 *frame;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-
-	/*
-	 *  Split frame into a number of segments
-	 */
-	while (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
-
-		/* Make new segment */
-		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
-		if (!frag)
-			return;
-
-		skb_reserve(frag, self->max_header_size);
-
-		/* Copy data from the original skb into this fragment. */
-		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
-		       self->max_seg_size);
-
-		/* Insert TTP header, with the more bit set */
-		frame = skb_push(frag, TTP_HEADER);
-		frame[0] = TTP_MORE;
-		
-		/* Hide the copied data from the original skb */
-		skb_pull(skb, self->max_seg_size);
-
-		/* Queue fragment */
-		skb_queue_tail(&self->tx_queue, frag);
-	}
-	/* Queue what is left of the original skb */
-	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
-	
-	frame = skb_push(skb, TTP_HEADER);
-	frame[0] = 0x00; /* Clear more bit */
-
-	/* Queue fragment */
-	skb_queue_tail(&self->tx_queue, skb);
-}
-
-/*
- * Function irttp_param_max_sdu_size (self, param)
- *
- *    Handle the MaxSduSize parameter in the connect frames, this function
- *    will be called both when this parameter needs to be inserted into, and
- *    extracted from the connect frames
- */
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
-				    int get)
-{
-	struct tsap_cb *self;
-
-	self = (struct tsap_cb *) instance;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
-	if (get)
-		param->pv.i = self->tx_max_sdu_size;
-	else
-		self->tx_max_sdu_size = param->pv.i;
-
-	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
-	
-	return 0;
-}
-
-/*
- * Function irttp_todo_expired (data)
- *
- *    Todo timer has expired!
- *
- */
-static void irttp_todo_expired(unsigned long data)
-{
-	struct tsap_cb *self = (struct tsap_cb *) data;
-
-	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC)
-		return;
-	
-	irttp_run_rx_queue(self);
-	irttp_run_tx_queue(self);
-		
-	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
-	{
+	self->avail_credit = (self->initial_credit -
+			      (self->remote_credit +
+			       skb_queue_len(&self->rx_queue) +
+			       skb_queue_len(&self->rx_fragments)));
+
+	/* Do we have too much credits to send to peer ? */
+	if ((self->remote_credit <= TTP_RX_MIN_CREDIT) &&
+	    (self->avail_credit > 0)) {
+		/* Send explicit credit frame */
 		irttp_give_credit(self);
+		/* Note : do *NOT* check if tx_queue is non-empty, that
+		 * will produce deadlocks. I repeat : send a credit frame
+		 * even if we have something to send in our Tx queue.
+		 * If we have credits, it means that our Tx queue is blocked.
+		 *
+		 * Let's suppose the peer can't keep up with our Tx. He will
+		 * flow control us by not sending us any credits, and we
+		 * will stop Tx and start accumulating credits here.
+		 * Up to the point where the peer will stop its Tx queue,
+		 * for lack of credits.
+		 * Let's assume the peer application is single threaded.
+		 * It will block on Tx and never consume any Rx buffer.
+		 * Deadlock. Guaranteed. - Jean II
+		 */
 	}
 
-	/* Check if time for disconnect */
-	if (test_bit(0, &self->disconnect_pend)) {
-		/* Check if it's possible to disconnect yet */
-		if (skb_queue_empty(&self->tx_queue)) {
-			/* Make sure disconnect is not pending anymore */
-			clear_bit(0, &self->disconnect_pend);	/* FALSE */
-
-			/* Note : self->disconnect_skb may be NULL */
-			irttp_disconnect_request(self, self->disconnect_skb,
-						 P_NORMAL);
-			self->disconnect_skb = NULL;
-		} else {
-			/* Try again later */
-			irttp_start_todo_timer(self, 1*HZ);
-			
-			/* No reason to try and close now */
-			return;
-		}
-	}
-	
-	/* Check if it's closing time */
-	if (self->close_pend)
-		irttp_close_tsap(self);
-}
-
-/*
- * Function irttp_start_todo_timer (self, timeout)
- *
- *    Start todo timer. 
- *
- */
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
-{
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
-	del_timer(&self->todo_timer);
-	
-	self->todo_timer.data     = (unsigned long) self;
-	self->todo_timer.function = &irttp_todo_expired;
-	self->todo_timer.expires  = jiffies + timeout;
-
-	add_timer(&self->todo_timer);
+	/* Reset lock */
+	self->rx_queue_lock = 0;
 }
 
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.4.21-pre1/net/irda/parameters.c linux-2.4.21-pre2/net/irda/parameters.c
--- linux-2.4.21-pre1/net/irda/parameters.c	Fri Nov  9 14:22:17 2001
+++ linux-2.4.21-pre2/net/irda/parameters.c	Wed Dec 18 14:16:28 2002
@@ -28,6 +28,7 @@
  *     
  ********************************************************************/
 
+#include <linux/types.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
diff -urN linux-2.4.21-pre1/net/sunrpc/clnt.c linux-2.4.21-pre2/net/sunrpc/clnt.c
--- linux-2.4.21-pre1/net/sunrpc/clnt.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/sunrpc/clnt.c	Wed Dec 18 14:16:28 2002
@@ -43,6 +43,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
 
+static void	call_start(struct rpc_task *task);
 static void	call_reserve(struct rpc_task *task);
 static void	call_reserveresult(struct rpc_task *task);
 static void	call_allocate(struct rpc_task *task);
@@ -326,13 +327,9 @@
 		rpcauth_bindcred(task);
 
 	if (task->tk_status == 0)
-		task->tk_action = call_reserve;
+		task->tk_action = call_start;
 	else
 		task->tk_action = NULL;
-
-	/* Increment call count */
-	if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
-		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 void
@@ -359,26 +356,48 @@
 	if (RPC_ASSASSINATED(task))
 		return;
 
-	task->tk_action = call_reserve;
-	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
+	task->tk_action = call_start;
 }
 
 /*
- * 1.	Reserve an RPC call slot
+ * 0.  Initial state
+ *
+ *     Other FSM states can be visited zero or more times, but
+ *     this state is visited exactly once for each RPC.
  */
 static void
-call_reserve(struct rpc_task *task)
+call_start(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 
 	if (task->tk_msg.rpc_proc > clnt->cl_maxproc) {
-		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
-			clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
+		printk(KERN_ERR "%s (vers %d): bad procedure number %d\n",
+				clnt->cl_protname, clnt->cl_vers,
+				task->tk_msg.rpc_proc);
 		rpc_exit(task, -EIO);
 		return;
 	}
 
+	dprintk("RPC: %4d call_start %s%d proc %d (%s)\n", task->tk_pid,
+		clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc,
+		(RPC_IS_ASYNC(task) ? "async" : "sync"));
+
+	/* Increment call count */
+	rpcproc_count(clnt, task->tk_msg.rpc_proc)++;
+	clnt->cl_stats->rpccnt++;
+	task->tk_action = call_reserve;
+}
+
+/*
+ * 1.	Reserve an RPC call slot
+ */
+static void
+call_reserve(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+
 	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
+
 	if (!rpcauth_uptodatecred(task)) {
 		task->tk_action = call_refresh;
 		return;
@@ -387,7 +406,6 @@
 	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
 	task->tk_timeout = clnt->cl_timeout.to_resrvval;
-	clnt->cl_stats->rpccnt++;
 	xprt_reserve(task);
 }
 
@@ -645,7 +663,6 @@
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
-		clnt->cl_stats->rpcretrans++;
 		break;
 	default:
 		if (clnt->cl_chatty)
diff -urN linux-2.4.21-pre1/net/sunrpc/svc.c linux-2.4.21-pre2/net/sunrpc/svc.c
--- linux-2.4.21-pre1/net/sunrpc/svc.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/sunrpc/svc.c	Wed Dec 18 14:16:28 2002
@@ -333,8 +333,12 @@
 		}
 	} else {
 		dprintk("svc: calling dispatcher\n");
-		if (!versp->vs_dispatch(rqstp, statp))
+		if (!versp->vs_dispatch(rqstp, statp)) {
+			/* Release reply info */
+			if (procp->pc_release)
+				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
 			goto dropit;
+		}
 	}
 
 	/* Check RPC status result */
diff -urN linux-2.4.21-pre1/net/sunrpc/xprt.c linux-2.4.21-pre2/net/sunrpc/xprt.c
--- linux-2.4.21-pre1/net/sunrpc/xprt.c	Thu Nov 28 15:53:16 2002
+++ linux-2.4.21-pre2/net/sunrpc/xprt.c	Wed Dec 18 14:16:28 2002
@@ -1416,6 +1416,8 @@
 		sk->no_check = UDP_CSUM_NORCV;
 		xprt_set_connected(xprt);
 	} else {
+		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+		tp->nonagle = 1;	/* disable Nagle's algorithm */
 		sk->data_ready = tcp_data_ready;
 		sk->state_change = tcp_state_change;
 		xprt_clear_connected(xprt);
diff -urN linux-2.4.21-pre1/scripts/Configure linux-2.4.21-pre2/scripts/Configure
--- linux-2.4.21-pre1/scripts/Configure	Mon Jul  2 13:56:40 2001
+++ linux-2.4.21-pre2/scripts/Configure	Wed Dec 18 14:16:28 2002
@@ -343,24 +343,14 @@
 #
 # int processes an integer argument with optional limits
 #
-#	int question define default [min max]
+#	int question define default
 #
 function int () {
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
-	if [ $# -gt 3 ]; then
-	  min=$4
-	else
-	  min=-10000000    # !!
-	fi
-	if [ $# -gt 4 ]; then
-	  max=$5
-	else
-	  max=10000000     # !!
-	fi
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
+	  if expr "$ans" : '[0-9]*$' > /dev/null; then
             define_int "$2" "$ans"
 	    break
           else
