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

diff -urN linux-2.4.2-pre4/CREDITS linux/CREDITS
--- linux-2.4.2-pre4/CREDITS	Mon Dec  3 22:29:05 2001
+++ linux/CREDITS	Mon Dec  3 22:29:14 2001
@@ -2694,7 +2694,7 @@
 S: Austria
 
 N: Jeff Tranter
-E: Jeff_Tranter@Mitel.COM
+E: tranter@pobox.com
 D: Enhancements to Joystick driver
 D: Author of Sound HOWTO and CD-ROM HOWTO
 D: Author of several small utilities
@@ -3059,8 +3059,8 @@
 W: http://www.andante.org
 D: General kernel hacker
 D: SCSI iso9660 and ELF
-S: 17 Canterbury Square #101
-S: Alexandria, Virginia 22304
+S: 6389 Hawk View Lane
+S: Alexandria, Virginia 22312
 S: USA
 
 N: Niibe Yutaka
diff -urN linux-2.4.2-pre4/Documentation/Changes linux/Documentation/Changes
--- linux-2.4.2-pre4/Documentation/Changes	Mon Dec  3 22:29:05 2001
+++ linux/Documentation/Changes	Mon Dec  3 22:29:14 2001
@@ -31,7 +31,7 @@
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: December 11, 2000
+Last updated: January 11, 2001
 
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
@@ -53,7 +53,8 @@
 o  binutils               2.9.1.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
-o  e2fsprogs              1.19                    # tune2fs --version
+o  e2fsprogs              1.19                    # tune2fs
+o  reiserfsprogs          3.x.0b                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -99,11 +100,11 @@
 your kernel.  This change does, however, mean that you need a recent
 release of binutils.
 
-If you can, upgrade to the latest 2.9.5 binutils release.  Older
+If you can, upgrade to the latest 2.9.5 or 2.10 binutils release.  Older
 releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if
 at all possible.  The later releases of 2.9.1.0.x (anything where x >= 22)
-can and do compile the kernel properly, but there are many benefits
-to upgrading to 2.9.5 if you're up to it.
+can and do compile the kernel properly, but there are many benefits in
+upgrading to 2.9.5 or 2.10 if you're up to it.
 
 System utils
 ============
@@ -114,20 +115,6 @@
 DevFS is now in the kernel.  See Documentation/filesystems/devfs/* in
 the kernel source tree for all the gory details.
 
-System V shared memory is now implemented via a virtual filesystem.
-You do not have to mount it to use it. SYSV shared memory limits are
-set via /proc/sys/kernel/shm{max,all,mni}.  You should mount the
-filesystem under /dev/shm to be able to use POSIX shared
-memory. Adding the following line to /etc/fstab should take care of
-things:
-
-none		/dev/shm	shm		defaults	0 0
-
-Remember to create the directory that you intend to mount shm on if
-necessary (The entry is automagically created if you use devfs). You
-can set limits for the number of blocks and inodes used by the
-filesystem with the mount options nr_blocks and nr_inodes.
-
 The Logical Volume Manager (LVM) is now in the kernel.  If you want to
 use this, you'll need to install the necessary LVM toolset.
 
@@ -178,6 +165,14 @@
 The latest version of e2fsprogs fixes several bugs in fsck and
 debugfs.  Obviously, it's a good idea to upgrade.
 
+Reiserfsprogs
+-------------
+
+The reiserfsprogs package should be used for reiserfs-3.6.x
+(Linux kernels 2.4.x). It is a combined package and contains working
+versions of mkreiserfs, resize_reiserfs, debugreiserfs and
+reiserfsck. These utils work on both i386 and alpha platforms.
+
 Pcmcia-cs
 ---------
 
@@ -206,6 +201,14 @@
 
 to your /etc/modules.conf file.
 
+Powertweak
+----------
+
+If you are running v0.1.17 or earlier, you should upgrade to
+version v0.99.0 or higher. Running old versions may cause problems
+with programs using shared memory.
+
+
 Networking
 ==========
 
@@ -262,10 +265,19 @@
 *********
 
 egcs 1.1.2 (gcc 2.91.66)
----------
-o  <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2>
-o  <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2>
-o  <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2>
+------------------------
+o  <ftp://sourceware.cygnus.com/pub/gcc/releases/egcs-1.1.2/egcs-1.1.2.tar.bz2>
+
+gcc 2.95.2
+----------
+o  <ftp://ftp.gnu.org/pub/gnu/gcc/gcc-2.95.2.tar.gz>
+
+Gnu Make
+********
+
+Make 3.77
+--------
+o  <ftp://ftp.gnu.org/gnu/make/make-3.77.tar.gz>
 
 Binutils
 ********
@@ -274,20 +286,20 @@
 ------------
 o  <ftp://ftp.valinux.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz>
 
-2.10 series
-------------
-o  <ftp://ftp.valinux.com/pub/support/hjl/binutils/binutils-2.10.0.24.tar.bz2>
+2.9.5 and 2.10 series
+---------------------
+o  <ftp://ftp.valinux.com/pub/support/hjl/binutils/>
 
 System utilities
 ****************
 
 Util-linux
 ----------
-o  <ftp://ftp.win.tue.nl/pub/linux-local/utils/util-linux/util-linux-2.10o.tar.gz>
+o  <ftp://ftp.kernel.org/pub/linux/utils/util-linux/util-linux-2.10o.tar.gz>
 
 Ksymoops
 --------
-o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4>
+o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4/>
 
 Modutils
 --------
@@ -295,13 +307,17 @@
 
 Mkinitrd
 --------
-o  <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/mkinitrd-2.5-1.src.rpm>
+o  <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/mkinitrd-2.9-1.src.rpm>
 
 E2fsprogs
 ---------
 o  <ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-1.19.tar.gz>
 o  <ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-1.19.src.rpm>
 
+Reiserfsprogs
+-------------
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfs_utils-3.6.25-fsck-3.x.0b.tar.gz>
+
 LVM toolset
 -----------
 o  <http://linux.msede.com/lvm/>
@@ -322,6 +338,10 @@
 ------------------
 o  <http://www.urbanmyth.org/microcode/>
 
+Powertweak
+----------
+o  <http://powertweak.sourceforge.net>
+
 Network
 *******
 
@@ -331,7 +351,7 @@
 
 Isdn4k-utils
 ------------
-o  <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz>
+o  <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/isdn4k-utils.v3.1pre1.tar.gz>
 
 Netfilter
 ---------
diff -urN linux-2.4.2-pre4/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.2-pre4/Documentation/Configure.help	Mon Dec  3 22:29:05 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:29:15 2001
@@ -10793,11 +10793,10 @@
   Balanced trees are more efficient than traditional
   filesystem architectural foundations.
 
-  You can use reiserfs in all cases where you use the ext2fs file
-  system, and you will gain in speed and disk space.  It has fewer
-  worst case performance situations than other file systems
-  because balanced trees are hardier creatures than other algorithms
-  are (if that is not technical enough, read www.namesys.com....:-) )
+  In general, ReiserFS is as fast as ext2, but is very efficient
+  with large directories and small files.  Additional patches are
+  needed for NFS and quotas, please see www.reiserfs.org for
+  links.
 
   It is more easily extended to have features currently found in
   database and keyword search systems than block allocation based
@@ -10805,7 +10804,7 @@
   support plugins consistent with our motto ``It takes more than a
   license to make source code open.''
 
-  Read www.namesys.com to learn more about reiserfs.
+  Read www.reiserfs.org to learn more about reiserfs.
 
   Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
 
diff -urN linux-2.4.2-pre4/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.2-pre4/Documentation/DocBook/kernel-locking.tmpl	Mon Dec  3 22:29:05 2001
+++ linux/Documentation/DocBook/kernel-locking.tmpl	Mon Dec  3 22:29:15 2001
@@ -720,7 +720,8 @@
       halves without a lock.  Depending on their exact timing, they
       would either see the new element in the list with a valid 
       <structfield>next</structfield> pointer, or it would not be in the 
-      list yet.
+      list yet.  A lock is still required against other CPUs inserting
+      or deleting from the list, of course.
     </para>
 
     <para>
diff -urN linux-2.4.2-pre4/Documentation/filesystems/Locking linux/Documentation/filesystems/Locking
--- linux-2.4.2-pre4/Documentation/filesystems/Locking	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/filesystems/Locking	Mon Dec  3 22:29:15 2001
@@ -117,7 +117,7 @@
 
 --------------------------- address_space_operations --------------------------
 prototypes:
-	int (*writepage)(struct file *, struct page *);
+	int (*writepage)(struct page *);
 	int (*readpage)(struct file *, struct page *);
 	int (*sync_page)(struct page *);
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
@@ -126,8 +126,8 @@
 locking rules:
 	All may block
 		BKL	PageLocked(page)
-writepage:	no	yes
-readpage:	no	yes
+writepage:	no	yes, unlocks
+readpage:	no	yes, unlocks
 sync_page:	no	maybe
 prepare_write:	no	yes
 commit_write:	no	yes
@@ -135,6 +135,7 @@
 
 	->prepare_write(), ->commit_write(), ->sync_page() and ->readpage()
 may be called from the request handler (/dev/loop).
+	->readpage() and ->writepage() unlock the page.
 	->sync_page() locking rules are not well-defined - usually it is called
 with lock on page, but that is not guaranteed. Considering the currently
 existing instances of this method ->sync_page() itself doesn't look
@@ -285,26 +286,13 @@
 prototypes:
 	void (*open)(struct vm_area_struct*);
 	void (*close)(struct vm_area_struct*);
-	void (*unmap)(struct vm_area_struct*, unsigned long, size_t);
-	void (*protect)(struct vm_area_struct*, unsigned long, size_t, unsigned);
-	int (*sync)(struct vm_area_struct*, unsigned long, size_t, unsigned);
 	struct page *(*nopage)(struct vm_area_struct*, unsigned long, int);
-	struct page *(*wppage)(struct vm_area_struct*, unsigned long, struct page*);
-	int (*swapout)(struct page *, struct file *);
 
 locking rules:
 		BKL	mmap_sem
 open:		no	yes
 close:		no	yes
-sync:		no	yes
-unmap:		no	yes
 nopage:		no	yes
-swapout:	yes	yes
-wpppage:				(see below)
-protect:				(see below)
-
-->wppage() and ->protect() have no instances and nothing calls them; looks like
-they must die...
 
 ================================================================================
 			Dubious stuff
diff -urN linux-2.4.2-pre4/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt
--- linux-2.4.2-pre4/Documentation/filesystems/ntfs.txt	Tue May  2 13:46:53 2000
+++ linux/Documentation/filesystems/ntfs.txt	Mon Dec  3 22:29:15 2001
@@ -2,18 +2,25 @@
 =============
 
 To mount an NTFS volume, use the filesystem type 'ntfs'. The driver
-currently works only in read-only mode, with no fault-tolerance
-supported.  If you enable the experimental write support, make sure
-you can recover from a complete loss of data and also always run
-chkdsk from within Microsoft Windows NT after performing a write to
-a NTFS partition from Linux to detect any problems as early as 
-possible. For ftdisk support, limited success was reported with 
-volume sets on top of the md driver, although mirror and stripe 
-sets should work as well - if the md driver can be talked into 
-using the same layout as Windows NT.
+currently works only in read-only mode, with no fault-tolerance supported.
+
+If you enable the dangerous(!) write support, make sure you can recover
+from a complete loss of data. Also, download the Linux-NTFS project
+distribution from Sourceforge at http://sourceforge.net/projects/linux-ntfs/
+and always run the included ntfsfix utility after performing a write to an
+NTFS partition from Linux to fix some of the damage done by the Linux NTFS
+driver. You should run ntfsfix _after_ unmounting the partition in Linux but
+_before_ rebooting into Windows. During the next reboot into Windows, chkdsk
+will be run automatically to fix the remaining damage.
+
+For ftdisk support, limited success was reported with volume sets on top of
+the md driver, although mirror and stripe sets should work as well - if the
+md driver can be talked into using the same layout as Windows NT. However,
+using the md driver will fail if any of your NTFS partitions have an odd
+number of sectors.
 
 Please note that the experimental write support is limited to
-Windows NT4 and earlier versions.
+Windows NT4 and earlier versions at the moment.
 
 The ntfs driver supports the following mount options:
 iocharset=name      Character set to use when returning file names.
diff -urN linux-2.4.2-pre4/Documentation/i2c/smbus-protocol linux/Documentation/i2c/smbus-protocol
--- linux-2.4.2-pre4/Documentation/i2c/smbus-protocol	Thu Dec 16 13:59:38 1999
+++ linux/Documentation/i2c/smbus-protocol	Mon Dec  3 22:29:15 2001
@@ -31,7 +31,7 @@
 SMBus Write Quick
 =================
 
-This sends a single byte to the device, at the place of the Rd/Wr bit.
+This sends a single bit to the device, at the place of the Rd/Wr bit.
 There is no equivalent Read Quick command.
 
 A Addr Rd/Wr [A] P
diff -urN linux-2.4.2-pre4/Documentation/modules.txt linux/Documentation/modules.txt
--- linux-2.4.2-pre4/Documentation/modules.txt	Fri Dec 29 14:35:47 2000
+++ linux/Documentation/modules.txt	Mon Dec  3 22:29:15 2001
@@ -137,6 +137,39 @@
 since umsdos runs piggyback on msdos.
 
 
+Using modinfo:
+--------------
+
+Sometimes you need to know what parameters are accepted by a
+module or you've found a bug and want to contact the maintainer.
+Then modinfo comes in very handy.
+
+Every module (normally) contains the author/maintainer,
+a description and a list of parameters.
+
+For example "modinfo -a eepro100" will return:
+
+	Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>
+
+and "modinfo -d eepro100" will return a description:
+
+	Intel i82557/i82558 PCI EtherExpressPro driver
+
+and more important "modinfo -p eepro100" will return this list:
+
+	debug int
+	options int array (min = 1, max = 8)
+	full_duplex int array (min = 1, max = 8)
+	congenb int
+	txfifo int
+	rxfifo int
+	txdmacount int
+	rxdmacount int
+	rx_copybreak int
+	max_interrupt_work int
+	multicast_filter_limit int
+
+
 The "ultimate" utility:
 -----------------------
 
diff -urN linux-2.4.2-pre4/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- linux-2.4.2-pre4/Documentation/networking/decnet.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/networking/decnet.txt	Mon Dec  3 22:29:15 2001
@@ -145,7 +145,7 @@
  - What is in the /proc/decnet* files and /proc/sys/net/decnet/* files ?
  - Which services are you running ?
  - Which client caused the problem ?
- - How much data was being transfered ?
+ - How much data was being transferred ?
  - Was the network congested ?
  - If there was a kernel panic, please run the output through ksymoops
    before sending it to me, otherwise its _useless_.
diff -urN linux-2.4.2-pre4/Documentation/s390/TAPE linux/Documentation/s390/TAPE
--- linux-2.4.2-pre4/Documentation/s390/TAPE	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/TAPE	Mon Dec  3 22:29:15 2001
@@ -0,0 +1,125 @@
+Channel attached Tape device driver 
+
+-----------------------------WARNING-----------------------------------------
+This driver is considered to be EXPERIMENTAL. Do NOT use it in 
+production environments. Feel free to test it and report problems back to us. 
+-----------------------------------------------------------------------------
+
+The LINUX for zSeries tape device driver manages channel attached tape drives 
+which are compatible to IBM 3480 or IBM 3490 magnetic tape subsystems. This 
+includes various models of these devices (for example the 3490E). 
+
+
+Tape driver features 
+
+The device driver supports a maximum of 128 tape devices. 
+No official LINUX device major number is assigned to the zSeries tape device 
+driver. It allocates major numbers dynamically and reports them on system 
+startup. 
+Typically it will get major number 254 for both the character device front-end 
+and the block device front-end. 
+
+The tape device driver needs no kernel parameters. All supported devices 
+present are detected on driver initialization at system startup or module load.
+The devices detected are ordered by their subchannel numbers. The device with 
+the lowest subchannel number becomes device 0, the next one will be device 1 
+and so on. 
+
+
+Tape character device front-end 
+
+The usual way to read or write to the tape device is through the character 
+device front-end. The zSeries tape device driver provides two character devices
+for each physical device -- the first of these will rewind automatically when 
+it is closed, the second will not rewind automatically. 
+
+The character device nodes are named /dev/rtibm0 (rewinding) and /dev/ntibm0 
+(non-rewinding) for the first device, /dev/rtibm1 and /dev/ntibm1 for the 
+second, and so on. 
+
+The character device front-end can be used as any other LINUX tape device. You 
+can write to it and read from it using LINUX facilities such as GNU tar. The 
+tool mt can be used to perform control operations, such as rewinding the tape 
+or skipping a file. 
+
+Most LINUX tape software should work with either tape character device. 
+
+
+Tape block device front-end 
+
+The tape device may also be accessed as a block device in read-only mode. 
+This could be used for software installation in the same way as it is used with 
+other operation systems on the zSeries platform (and most LINUX 
+distributions are shipped on compact disk using ISO9660 filesystems). 
+
+One block device node is provided for each physical device. These are named 
+/dev/btibm0 for the first device, /dev/btibm1 for the second and so on. 
+You should only use the ISO9660 filesystem on LINUX for zSeries tapes because 
+the physical tape devices cannot perform fast seeks and the ISO9660 system is 
+optimized for this situation. 
+
+
+Tape block device example 
+
+In this example a tape with an ISO9660 filesystem is created using the first 
+tape device. ISO9660 filesystem support must be built into your system kernel
+for this. 
+The mt command is used to issue tape commands and the mkisofs command to 
+create an ISO9660 filesystem: 
+
+- create a LINUX directory (somedir) with the contents of the filesystem 
+     mkdir somedir
+     cp contents somedir 
+
+- insert a tape 
+
+- ensure the tape is at the beginning 
+     mt -f /dev/ntibm0 rewind 
+
+- set the blocksize of the character driver. The blocksizes 512, 1024
+  and 2048 bytes are supported by ISO9660. 1024 is the default, u
+  which will be used here. 
+     mt -f /dev/ntibm0 setblk 1024 
+
+- write the filesystem to the character device driver 
+     mkisofs -o /dev/ntibm0 somedir 
+
+- rewind the tape again 
+     mt -f /dev/ntibm0 rewind 
+
+- Now you can mount your new filesystem as a block device: 
+     mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt 
+
+TODO List 
+
+- The backend code has to be enhanced to support error-recovery actions. 
+
+- The seeking algorithm of the block device has to be improved to speed 
+  things up 
+
+BUGS 
+
+There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL.
+If an error occurs which cannot be handled by the code you will get a 
+sense-data dump.In that case please do the following: 
+
+1. set the tape driver debug level to maximum: 
+     echo 6 >/proc/s390dbf/tape/level 
+
+2. re-perform the actions which produced the bug. (Hopefully the bug will 
+   reappear.) 
+
+3. get a snapshot from the debug-feature: 
+     cat /proc/s390dbf/tape/hex_ascii >somefile 
+
+4. Now put the snapshot together with a detailed description of the situation 
+   that led to the bug: 
+ - Which tool did you use? 
+ - Which hardware do you have? 
+ - Was your tape unit online? 
+ - Is it a shared tape unit? 
+
+5. Send an email with your bug report to: 
+     mailto:Linux390@de.ibm.com 
+
+
diff -urN linux-2.4.2-pre4/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt
--- linux-2.4.2-pre4/Documentation/s390/cds.txt	Thu Oct 12 14:19:31 2000
+++ linux/Documentation/s390/cds.txt	Mon Dec  3 22:29:15 2001
@@ -539,7 +539,7 @@
 
 Possible flag values are :
 
-DOIO_EARLY_NOTIFICATION  - allow for early interupt notification
+DOIO_EARLY_NOTIFICATION  - allow for early interrupt notification
 DOIO_VALID_LPM           - LPM input parameter is valid (see usage
                            notes below for details)
 DOIO_WAIT_FOR_INTERRUPT  - wait synchronously for final status
@@ -549,7 +549,7 @@
 
 typedef struct {
    char            cmd_code; /* command code */
-   char            flags;    /* flags, like IDA adressing, etc. */
+   char            flags;    /* flags, like IDA addressing, etc. */
    unsigned short  count;    /* byte count */
    void           *cda;      /* data address */
 } ccw1_t __attribute__ ((aligned(8)));
diff -urN linux-2.4.2-pre4/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8
--- linux-2.4.2-pre4/Documentation/s390/chandev.8	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/chandev.8	Mon Dec  3 22:29:15 2001
@@ -0,0 +1,306 @@
+.TH chandev 8
+.SH NAME
+channel device layer
+.Dd December 6, 2000
+.Os Linux for Zseries
+
+.SH SYNOPSIS
+The channel device layer is a layer to provide a consistent interface for
+configuration & default machine check (devices appearing & disappearing )
+handling Linux for zSeries channel devices.
+
+These include among others
+
+.Bl -item
+.It
+lcs ( the most common ethernet/token ring/fddi standard on zSeries )
+.It
+ctc/escon hi speed like serial link standard on zSeries.
+.It
+claw used to talk to cisco routers.
+.It
+qeth gigabit ethernet.
+.El
+
+These devices use two channels one read & one write for configuration &
+or communication.
+The motivation behind producing this layer was that there is a lot of
+duplicate code among the drivers for configuration so the lcs & ctc drivers
+tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172
+lcs compatible devices or escons/ctc's & to resolve this fight
+both device drivers had to be reconfigured rather than doing the
+configuration in a single place.
+
+.SH DESCRIPTION
+The current setup can be read from /proc/chandev
+arguments can be entered by...
+.Bl -enum
+.It
+Piping to /proc/chandev.
+.It
+Entering them into /etc/chandev.conf comments are prefixed #.
+.It
+Or from the boot command line using the 'chandev=' keyword
+.El
+Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows.
+/bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>.
+
+e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the  parameters would be.
+
+
+/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone
+
+
+This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone.
+
+valid chandev arguments are <> indicate optional parameters, | indicate a choice.
+
+.B glossary
+.Bl -item
+.It
+devno: is a 16 bit unsigned number used to uniquely identify a subchannel to a device.
+.It
+force list: is a term specific to channel device layer describing a range of devno's to be forced to configure in a particular manner as opposed to autodetect
+.El
+
+.B commonly used options
+
+.Bl -item
+.It
+
+.Bl -item
+
+.It
+.B (ctc|escon|lcs|osad|qeth|claw)<devif_num>, 
+read_devno, write_devno, <port_no/protocol_no>, <checksum_received_ip_pkts>, <use_hw_stats>
+.It
+e.g. ctc0,0x7c00,0x7c01,0,0,0
+.It
+Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter.
+.El
+.It
+
+.Bl -item
+.It
+.B add_parms
+,chan_type,<string>
+.It
+chan_type bitfield 
+.It
+ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20.
+.It
+This is for device driver specific options passed as a string to the driver
+not dealt with by the channel device layer it can't contain spaces.
+.El
+.It
+
+.Bl -item
+.It
+.B del_parms
+<,chan_type,exact_match>
+.It
+This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type.
+.El
+.It
+
+.Bl -item
+.It
+.B noauto
+,<lo_devno>-<hi_devno>
+.It
+Don't probe a range of device numbers for channel devices.
+.El
+.It
+
+.Bl -item
+.It
+.B use_devno_names
+.It
+Tells the channel layer to assign device names based on the read channel cuu number.
+.It
+e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices.
+.El
+.El
+
+
+.B power user options
+
+
+.Bl -item
+
+.It
+.Bl -item
+.It
+.B del_noauto
+,<devno>
+.It
+ Delete a range or all noauto ranges when devno is within a range.
+.El
+
+.It
+.Bl -item
+.It
+.B del_force
+,read_devno
+.It
+Delete a forced channel device from force list.
+.El
+
+.It
+.Bl -item
+.It
+.B dont_use_devno_names
+.It
+Opposite to use_devno_names described above.
+.El
+
+
+.It
+.Bl -item
+.It
+.B add_model
+,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling
+
+.It
+Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard.
+Set max_port_no to 0 for non lcs devices.
+.It
+auto machine check recovery bitfield
+.It
+not_operational=0x1, no_path=0x2, revalidate=0x4, gone=0x8
+.It
+chan_type bitfield
+.It
+ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20
+
+.It
+.Bl -item
+.It
+.B del_model
+,cu_type,cu_model,dev_type,dev_model
+.It
+-1 for any parameter is a wildcard,
+.El
+.It
+.B del_all_models
+.It
+.Bl -item
+.It
+.B auto_msck
+<,lo_devno>,<hi_devno>,auto_msck_recovery
+.It
+This is used to specify the kind of machine check recovery that occurs over a device range.
+.El
+.It
+.Bl -item
+.It
+.B del_auto_msck
+<,devno>
+.It
+Delete a range or all machine check recovery ranges when devno is within a range.
+.El
+.It
+.Bl -item
+.It
+.B reset_clean
+.It
+Resets all model info, forced devices & noauto lists to null.
+.El
+.It
+.Bl -item
+.It
+.B reset_conf
+.It
+Resets all model info, forced devices & noauto lists back to default settings.
+.El
+.It
+.Bl -item
+.It
+.B reset_conf_clean
+.It
+Resets all model info, forced devices & noauto lists to empty.
+.El
+.It
+.Bl -item
+.It
+.B shutdown
+<device name|read devno>
+.It
+Shuts down a particular device by device name or read devno,
+deregisters it & releases its interrupts
+or shuts down all devices if no parameter is used.
+.El
+.It
+.Bl -item
+.It
+.B reprobe
+.It
+Calls probe method for channels whose interrupts are not owned.
+.El
+.It
+.Bl -item
+.It
+.B read_conf
+.It
+Read instructions from /etc/chandev.conf.
+.El
+.It
+.Bl -item
+.It
+.B dont_read_conf
+.It
+Don't automatically read /etc/chandev.conf on boot.
+.El
+.It
+e.g the following sequence of commands should be roughly equivalent
+to rebooting for channel devices.
+.Bl -item
+.It
+shutdown
+.It
+reset_conf
+.It
+read_conf
+.It
+reprobe
+.El
+.El
+
+.SH SEE ALSO
+.Bl -item
+.It
+If you wish to write a driver channel device layer compatible
+.It
+/linux/include/asm-s390/chandev.h for the apis which are commented.
+.It
+/linux/drivers/s390/misc/chandev.c for the code.
+.El
+
+.SH FILES
+.Bl -item
+.It
+.B /proc/chandev
+.It
+cat /proc/chandev to see current options chosen.
+.Iy
+echo <command> >proc/chandev to enter a new command
+.It
+.B /etc/chandev.conf 
+.It
+A file which can be used to configure the channel 
+device layer.
+.It
+kernel parameters with the 
+.B 'chandev=' 
+keyword.
+.It
+.B /bin/chandev
+.It 
+A user script/executable which is run when devices come online "appear"
+or go offline "disappear".
+.El
+
+
+.SH AUTHORS
+DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+
diff -urN linux-2.4.2-pre4/Documentation/sound/AWE32 linux/Documentation/sound/AWE32
--- linux-2.4.2-pre4/Documentation/sound/AWE32	Tue Apr 11 19:13:15 2000
+++ linux/Documentation/sound/AWE32	Mon Dec  3 22:29:15 2001
@@ -3,103 +3,74 @@
 This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and 
 SB32.
 
-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This is 
-important, because the driver works only with real Creative cards.
+1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
+   is important, because the driver works only with real Creative cards.
 
-2) If your card is NOT "Plug-n-Play" then go to 5th step now. In the other case
-proceed to step 3.
+2) The first thing you need to do is re-compile your kernel with support for
+   your sound card. Run your favourite tool to configure the kernel and when
+   you get to the "Sound" menu you should enable support for the following:
 
-3) You should compile in kernel ISAPnP support or you should obtain isapnptools.
-If you choose kernel level ISAPnP skip to step 5. I looked through other PnP 
-packages for Linux, but all they are either in deep unstable beta/alpha releases
-or they are much worse than isapnptools. In my case isapnptools were included in
-a Linux distribution (Red Hat 5.x). If you also already have them then go to 
-step 4.
+   Sound card support,
+   OSS sound modules,
+   100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
+   AWE32 synth
 
-The latest copy of isapnptools-1.17 is available from 
-ftp://sunsite.unc.edu/pub/Linux/system/hardware/isapnptools-1.17.tgz
-You should gunzip/untar it to something like /usr/local/ 
-(cp isapnptools-1.17.tgz /usr/local/; cd /usr/local/;
-tar -xzf isapnptools-1.17.tgz). 
+   If your card is "Plug and Play" you will also need to enable these two
+   options, found under the "Plug and Play configuration" menu:
 
-Compile the package (make) and install it (make install).
-If something goes wrong check the INSTALL file in isapnptools-1.15 directory.
+   Plug and Play support
+   ISA Plug and Play support
 
-4) Now do a "pnpdump > /etc/isapnp.conf". File /etc/isapnp.conf will contain 
-info about PnP devices you may have. If you want you can read the manual page
-about isapnp.conf file (man isapnp.conf). Most lines of your isapnp.conf file are 
-commented. You should uncomment lines which don't conflict with your 
-configuration.
+   Now compile and install the kernel in normal fashion. If you don't know
+   how to do this you can find instructions for this in the README file
+   located in the root directory of the kernel source.
 
-ATTENTION! Device Audio should have 1 IRQ, 2 DMA and 3 base I/O resources.
-If you don't have such a configuration you should manually add the resources to
-the isapnp.conf file. After editing I got these lines in the Audio device
-section (I ripped out all the comments):
+3) Before you can start playing midi files you will have to load a sound
+   bank file. The utility needed for doing this is called "sfxload", and it
+   is one of the utilities found in a package called "awesfx". If this
+   package is not available in your distribution you can download the AWE
+   snapshot from Creative Labs Open Source website:
 
-"(CONFIGURE CTL0044/1132685 (LD 0 (INT 0 (IRQ 5 (MODE +E))) (DMA 0 (CHANNEL 1))
- (DMA 1 (CHANNEL 5)) (IO 0 (BASE 0x220)) (IO 1 (BASE 0x330)) (IO 2 (BASE 0x388))
- (ACT Y)))"
+   http://www.opensource.creative.com/snapshot.html
 
-(In your case CTL044/1132685 numbers may be other)
+   Once you have unpacked the AWE snapshot you will see a "awesfx"
+   directory. Follow the instructions in awesfx/docs/INSTALL to install the
+   utilities in this package. After doing this, sfxload should be installed
+   as:
 
-Don't forget to uncomment (ACT Y)!
+   /usr/local/bin/sfxload
 
-The next device is the on-board IDE controller. You may enable it if you wish,
-but it will not effect sound.
+   To enable AWE general midi synthesis you should also get the sound bank
+   file for general midi from:
 
-Then WaveTable goes. For some reason Plug-n-Play detects only one I/O port,
-but the wavetable needs THREE! My working string is:
+   http://members.xoom.com/yar/synthgm.sbk.gz
 
-"(CONFIGURE CTL044/1132685 (LD 2 (IO 0 (BASE 0x0620)) (IO 1 (BASE 0x0A20)) 
-(IO 2 (BASE 0x0E20)) (ACT Y) ))"
+   Copy it to a directory of your choice, and unpack it there.
 
-Resources 0x0620, 0x0A20 and 0x0E20 should work. Other on-board devices: 
-Gameport and StereoEnhance are not required to be initialized.
+4) Edit /etc/modules.conf, and insert the following lines at the end of the
+   file:
 
-Now you can execute "isapnp /etc/isapnp.conf". No errors should be reported.
-If you correctly installed isapnptools, then isapnp will run every boot time.
+  alias sound-slot-0 sb
+  alias sound-service-0-1 awe_wave
+  post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
 
-5) Now you should recompile the kernel.
+  You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
+  path of of the sound bank file. That will enable the Sound Blaster and AWE
+  wave synthesis. To play midi files you should get one of these programs if
+  you don't already have them:
 
-In "make (x,menu)config" select in "Sound":
-"Sound card support", "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support",
-"Generic OPL2/OPL3 FM synthesizer support" and "FM synthesizer (YM3812/OPL-3) 
-support" as <M> (module).
+  Playmidi:			http://playmidi.openprojects.net
 
-In "make (x,menu)config" select in "Sound":
-select "OSS sound modules" as <M> (module)
-select "AWE32 Synth" as <M> (module)
+  AWEMidi Player (drvmidi)  	Included in the previously mentioned AWE
+  				snapshot.
 
-Now recompile the kernel (make dep; make (b)zImage, b(z)lilo, etc...;
-make modules; make modules_install), update your boot loader (if required) and
-boot new kernel.
+  You will probably have to pass the "-e" switch to playmidi to have it use
+  your midi device. drvmidi should work without switches.
 
-6) If awesfx program is not included in your distribution, then download it 
-from http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest.
-Compile it. Copy sfxload program to /usr/bin. To enable AWE general midi
-synthesis you should also get the sound bank file for general midi from
-http://members.xoom.com/yar/synthgm.sbk.gz. Copy it to /usr and gunzip it there.
+  If something goes wrong please e-mail me. All comments and suggestions are
+  welcome.
 
-7) Edit /etc/modules.conf, inserting at the end of the file:
+		    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
+			    http://www.yar.opennet.ru
 
-alias midi awe_wave
-post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk
-
-That will enable the Sound Blaster and AWE wave synthesis.
-
-To play midi files you should get one of these programs:
-
-Playmidi 2.4 or higher: http://playmidi.openprojects.net
-Drvmidi: http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest
-
-(These are available at all major Linux FTP sites and may already be
- in your distribution)
-Remember to use -a switch if you have playmidi as a compiled binary (ex. RPM)
-
-If something goes wrong please e-mail me. All comments and suggestions are
-welcome.
-
-			    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
-				    http://www.yar.opennet.ru
-
-Last Updated: 10Apr2000
+Last Updated: Feb 3 2001
diff -urN linux-2.4.2-pre4/Documentation/sound/Introduction linux/Documentation/sound/Introduction
--- linux-2.4.2-pre4/Documentation/sound/Introduction	Wed Sep 27 13:53:52 2000
+++ linux/Documentation/sound/Introduction	Mon Dec  3 22:29:15 2001
@@ -1,15 +1,19 @@
 Introduction	Notes on Modular Sound Drivers and Soundcore
 Wade Hampton 
-6/30/1999
+2/14/2001
 
 Purpose:  
 ========
 This document provides some general notes on the modular 
 sound drivers and their configuration, along with the 
-support modules sound.o, soundlow.o and soundcore.o.
+support modules sound.o and soundcore.o.
 
 Note, some of this probably should be added to the Sound-HOWTO!
 
+Note, soundlow.o was present with 2.2 kernels but is not 
+required for 2.4.x kernels.  References have been removed
+to this.
+
 
 Copying:
 ========
@@ -28,6 +32,8 @@
 1.1.1  19991031	   Added notes on sound-slot- and sound-service.
 			(Alan Cox)
 1.1.2  20000920    Modified for Kernel 2.4 (Christoph Hellwig)
+1.1.3  20010214    Minor notes and corrections (Wade Hampton)
+                   Added examples of sound-slot-0, etc.
 
 
 Modular Sound Drivers:
@@ -69,8 +75,9 @@
 
 1.  There is a new OpenSource sound driver called ALSA which is
     currently under development:  http://www.alsa-project.org/
-    I have not tried it nor am I aware of its status, but it is
-    currently under development.
+    The ALSA drivers support some newer hardware that may not 
+    be supported by this sound driver and also provide some 
+    additional features.
 
 2.  The commercial OSS driver may be obtained from the site:
     http://www/opensound.com.  This may be used for cards that
@@ -82,7 +89,8 @@
     some of the requirements for multiple sound card systems.  For
     more information, see:  http://www.tux.org/~ricdude/EsounD.html  
     The "esd" program may be used with the real-player and mpeg 
-    players like mpg123 and x11amp.
+    players like mpg123 and x11amp.  The newer real-player 
+    and some games even include built-in support for ESD!
 
 
 Building the Modules:
@@ -104,13 +112,31 @@
 
 4.  Select your sound driver(s) as a module.  For ProAudio, Sound
     Blaster, etc., select M (module) for OSS sound modules.
-    [thanks to marvin stodolsky <stodolsk@erols.com>]A
+    [thanks to Marvin Stodolsky <stodolsk@erols.com>]A
 
 5.  Make the kernel (e.g., make dep ; make bzImage), and install
     the kernel.
 
 6.  Make the modules and install them (make modules; make modules_install).
 
+Note, for 2.4.x kernels, make sure you have the newer modutils 
+loaded or modules will not be loaded properly.  2.4.x changed the 
+layout of /lib/modules/2.4.x and requires an updated modutils.
+
+
+Plug and Play (PnP:
+===================
+
+If the sound card is an ISA PnP card, isapnp may be used
+to configure the card.  See the file isapnp.txt in the 
+directory one level up (e.g., /usr/src/linux/Documentation).
+
+Also the 2.4.x kernels provide PnP capabilities, see the 
+file NEWS in this directory.
+
+PCI sound cards are highly recommended, as they are far 
+easier to configure and from what I have read, they use
+less resources and are more CPU efficient.
 
 
 INSMOD:
@@ -129,7 +155,6 @@
 #
 echo Starting sound
 /sbin/insmod soundcore
-/sbin/insmod soundlow
 /sbin/insmod sound  
 #
 echo Starting sound blaster....
@@ -160,6 +185,10 @@
 The status of sound may be read/checked by:
         cat (anyfile).au >/dev/audio
 
+[WWH:  This may not work properly for SoundBlaster PCI 128 cards
+such as the es1370/1 (see the es1370/1 files in this directory) 
+as they do not automatically support uLaw on /dev/audio.]
+
 The status of the modules and which modules depend on 
 which other modules may be checked by:
 	/sbin/lsmod
@@ -168,7 +197,6 @@
 	sb                     26280   0 
 	uart401                 5640   0  [sb]
 	sound                  57112   0  [sb uart401]
-	soundlow                 208   0  [sound]
 	soundcore               1968   8  [sb sound]
 
 
@@ -186,7 +214,6 @@
 /sbin/rmmod sb
 /sbin/rmmod uart401
 /sbin/rmmod sound
-/sbin/rmmod soundlow
 /sbin/rmmod soundcore
 
 When using sound as a module, I typically put these commands
@@ -217,7 +244,8 @@
 Typically, you need two sound cards of different types.  Note, this
 uses more precious interrupts and DMA channels and sometimes 
 can be a configuration nightmare.  I have heard reports of 3-4
-sound cards (typically I only use 2).
+sound cards (typically I only use 2).  You can sometimes use
+multiple PCI sound cards of the same type.
 
 On my machine I have two sound cards (cs4232 and Soundblaster Vibra
 16).  By loading sound as modules, I can control which is the first
@@ -236,7 +264,7 @@
 
 1.  Copy the sound modules to a new name.  For example
     sb.o could be copied (or symlinked) to sb1.o for the
-    second SoundBlasster.
+    second SoundBlaster.
 
 2.  Make a second entry in /etc/modules.conf, for example,
     sound1 or sb1.  This second entry should refer to the
@@ -257,6 +285,7 @@
 supports multiple cards with one module by default.
 Read the file 'Soundblaster' in this directory for details.
 
+
 Sound Problems:
 ===============
 
@@ -314,7 +343,6 @@
     esddsp <program> may be used to play files via a non-esd
     aware program.
 
-
 6)  Ask for help on the sound list or send E-MAIL to the
     sound driver author/maintainer.
 
@@ -327,6 +355,9 @@
 
     This makes the sound system allocate its buffers and hang onto them.
 
+    You may also set persistent DMA when building a 2.4.x kernel.
+
+
 Configuring Sound:
 ==================
 
@@ -354,10 +385,11 @@
 
 Anyone want to write a linuxconf module for configuring sound?
 
+
 Module Loading:
 ===============
 
-When a sound card is first referenced and sound is modular the sound system
+When a sound card is first referenced and sound is modular, the sound system
 will ask for the sound devices to be loaded. Initially it requests that
 the driver for the sound system is loaded. It then will ask for 
 sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and
@@ -370,11 +402,32 @@
 a midi synth in all cases then it will request "sound-service-0-n" where n
 is
 
-0	Mixer
+  0	Mixer
+
+  2  	MIDI
+
+  3, 4	DSP audio
+
 
-2  	MIDI
+For example, I use the following to load my Soundblaster PCI 128
+(ES 1371) card first, followed by my SoundBlaster Vibra 16 card,
+then by my TV card:
 
-3, 4	DSP audio
+# Load the Soundblaster PCI 128 as /dev/dsp, /dev/dsp1, /dev/mixer
+alias sound-slot-0 es1371
+
+# Load the Soundblaster Vibra 16 as /dev/dsp2, /dev/mixer1
+alias sound-slot-1 sb
+options sb io=0x240 irq=5 dma=1 dma16=5 mpu_io=0x330
+
+# Load the BTTV (TV card) as /dev/mixer2
+alias sound-slot-2 bttv
+alias sound-service-2-0 tvmixer
+
+pre-install bttv  modprobe tuner ; modprobe tvmixer
+pre-install tvmixer modprobe msp3400; modprobe tvaudio 
+options tuner debug=0 type=8 
+options bttv  card=0 radio=0 pll=0
 
 
 For More Information (RTFM):
@@ -405,3 +458,4 @@
 Contact Information:
 ====================
 Wade Hampton:  (whampton@staffnet.com)
+
diff -urN linux-2.4.2-pre4/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.2-pre4/Documentation/video4linux/bttv/CARDLIST	Sun Nov 12 20:47:19 2000
+++ linux/Documentation/video4linux/bttv/CARDLIST	Mon Dec  3 22:29:15 2001
@@ -38,36 +38,50 @@
   card=36 - Typhoon TView TV/FM Tuner
   card=37 - PixelView PlayTV pro
   card=38 - TView99 CPH063
-  card=39 - Pinnacle PCTV Rave
+  card=39 - Pinnacle PCTV Studio/Rave
   card=40 - STB2
   card=41 - AVerMedia TVPhone 98
   card=42 - ProVideo PV951
   card=43 - Little OnAir TV
   card=44 - Sigma TVII-FM
   card=45 - MATRIX-Vision MV-Delta 2
-  card=46 - Zoltrix Genie TV
+  card=46 - Zoltrix Genie TV/FM
   card=47 - Terratec TV/Radio+
   card=48 - Dynalink Magic TView 
   card=49 - GV-BCTV3
   card=50 - Prolink PV-BT878P+4E (PixelView PlayTV PAK)
   card=51 - Eagle Wireless Capricorn2 (bt878A)
-  card=52 - Pinnacle Studio PCTV Pro
-  card=53 - Typhoon TView RDS
+  card=52 - Pinnacle PCTV Studio Pro
+  card=53 - Typhoon TView RDS / FM Stereo
+  card=54 - Livetec 9415 TV
+  card=55 - BESTBUY Easy TV
+  card=56 - FlyVideo '98/FM
+  card=57 - GrandTec 'Grand Video Capture'
+  card=58 - Phoebe TV Master Only (No FM)
 
 tuner.o
-  type=0 - Temic PAL
+  type=0 - Temic PAL (4002 FH5)
   type=1 - Philips PAL_I
   type=2 - Philips NTSC
   type=3 - Philips SECAM
   type=4 - NoTuner
   type=5 - Philips PAL
-  type=6 - Temic NTSC
-  type=7 - Temic PAL_I
-  type=8 - Temic 4036 FY5 NTSC
+  type=6 - Temic NTSC (4032 FY5)
+  type=7 - Temic PAL_I (4062 FY5)
+  type=8 - Temic NTSC (4036 FY5)
   type=9 - Alps HSBH1
   type=10 - Alps TSBE1
   type=11 - Alps TSBB5
   type=12 - Alps TSBE5
   type=13 - Alps TSBC5
-  type=14 - Temic 4006FH5
+  type=14 - Temic PAL_I (4006FH5)
   type=15 - Alps TSCH6
+  type=16 - Temic PAL_DK (4016 FY5)
+  type=17 - Philips NTSC_M (MK2)
+  type=18 - Temic PAL_I (4066 FY5)
+  type=19 - Temic PAL* auto (4006 FN5)
+  type=20 - Temic PAL (4009 FR5)
+  type=21 - Temic NTSC (4039 FR5)
+  type=22 - Temic PAL/SECAM multi (4046 FM5)
+  type=23 - Philips PAL_DK
+  type=24 - Philips PAL/SECAM multi (FQ1216ME)
diff -urN linux-2.4.2-pre4/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options
--- linux-2.4.2-pre4/Documentation/video4linux/bttv/Insmod-options	Sat Dec 30 11:23:13 2000
+++ linux/Documentation/video4linux/bttv/Insmod-options	Mon Dec  3 22:29:15 2001
@@ -30,6 +30,12 @@
 				default is 2.
 		gbufsize=	size of capture buffers. default and
 				maximum value is 0x208000 (~2MB)
+		no_overlay=0	Enable overlay on broken hardware.  There
+				are some chipsets (SIS for example) which
+				are known to have problems with the PCI DMA
+				push used by bttv.  bttv will disable overlay
+				by default on this hardware to avoid crashes.
+				With this insmod option you can override this.
 
 		bttv_gpio=0/1
 		gpiomask=
@@ -48,6 +54,8 @@
 		debug=1		print some debug info to the syslog
 		type=n		type of the tuner chip. n as follows:
 				see CARDLIST for a complete list.
+		pal=[bdgil]	select PAL variant (used for some tuners
+				only, important for the audio carrier).
 
 tvmixer.o
 	registers a mixer device for the TV card's volume/bass/treble
diff -urN linux-2.4.2-pre4/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README
--- linux-2.4.2-pre4/Documentation/video4linux/bttv/README	Sat Dec 30 11:23:13 2000
+++ linux/Documentation/video4linux/bttv/README	Mon Dec  3 22:29:15 2001
@@ -16,9 +16,10 @@
 kernel, download it from:
 	http://www2.lm-sensors.nu/~lm78/download.html
 
-You'll need at least these i2c config options for bttv:
+You'll need at least these config options for bttv:
 CONFIG_I2C=m
 CONFIG_I2C_ALGOBIT=m
+CONFIG_VIDEO_DEV=m
 
 The latest bttv version is available here:
 	http://www.strusel007.de/linux/bttv/
@@ -50,12 +51,8 @@
 Make bttv work with your card
 -----------------------------
 
-Of course you have to load the modules as very first thing.  The
-separate bttv bundle comes with a script called "update".  I use this
-one to load a new version while doing driver hacking.  You can use it
-too, but check the module arguments first.  They work for my setup,
-and probably do *not* for yours.  Another way is to setup your
-/etc/modules.conf file and let kmod load the modules.  See also:
+Setup your /etc/modules.conf file and let kmod load the modules.
+See also:
 
 Modules.conf:	some sample entries for /etc/modules.conf
 Insmod-options:	list of all insmod options available for bttv and
@@ -68,15 +65,45 @@
 to load them automagically by calling request_module() now, but this
 obviously works only with kmod enabled.
 
+If bttv takes very long to load (happens sometimes with the cheap
+cards which have no tuner), try adding this to your modules.conf:
+	options i2c-algo-bit bit_test=1
+
 The most important insmod option for bttv is "card=n" to select the
-correct card type.  If you get video but no sound you've very likely
-specified the wrong (or no) card type.  A list of supported cards is
-in CARDLIST.
+correct card type in case the autodetection does'nt work. If you get
+video but no sound you've very likely specified the wrong (or no)
+card type.  A list of supported cards is in CARDLIST.
 
 If your card isn't listed in CARDLIST or if you have trouble making
 audio work, you should read the Sound-FAQ.
 
 
+Autodetecting cards
+-------------------
+
+bttv uses the PCI Subsystem ID to autodetect the card type.  lspci lists
+the Subsystem ID in the second line, looks like this:
+
+00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
+        Subsystem: Hauppauge computer works Inc. WinTV/GO
+        Flags: bus master, medium devsel, latency 32, IRQ 5
+        Memory at e2000000 (32-bit, prefetchable) [size=4K]
+
+only bt878-based cards can have a subsystem ID (which does not mean
+that every card really has one).  bt848 cards can't have a Subsystem
+ID and therefore can't be autodetected.  There is a list with the ID's
+in bttv-cards.c (in case you are intrested or want to mail patches
+with updates).
+
+Old driver versions used to have a heuristic which could identify some
+bt848-based cards.  It worked for Hauppauge and Miro cards in most
+cases (simply because these where the first cards available on the
+market), but misdetected other bt848 cards.  That code is gone now for
+exactly this reason, the misdetection confused lots of people.  If you
+have a old Hauppauge or Miro card, you'll have to load the driver with
+card=1 or card=2 these days.
+
+
 Still doesn't work?
 -------------------
 
@@ -87,10 +114,12 @@
 yourself (patches very welcome of course...)  You know: The linux
 slogan is "Do it yourself".
 
-There is a mailing list: video4linux-list@redhat.com.  If you have
-trouble with some specific TV card, try to ask there instead of
-mailing me directly.  The chance that someone with the same card
-listens there is much higher...
+There is a mailing list: video4linux-list@redhat.com.
+https://listman.redhat.com/mailman/listinfo/video4linux-list
+
+If you have trouble with some specific TV card, try to ask there
+instead of mailing me directly.  The chance that someone with the
+same card listens there is much higher...
 
 For problems with sound:  There are alot of different systems used
 for TV sound all over the world.  And there are also different chips
diff -urN linux-2.4.2-pre4/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ
--- linux-2.4.2-pre4/Documentation/video4linux/bttv/Sound-FAQ	Sun Nov 12 20:47:19 2000
+++ linux/Documentation/video4linux/bttv/Sound-FAQ	Mon Dec  3 22:29:15 2001
@@ -79,10 +79,12 @@
 What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
-values used by the windows driver.  A tool to do this is available
-from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil (doesn't
-work with bt878 boards according to some reports I received).  You
-might also dig around in the *.ini files of the Windows applications.
+values used by the windows driver.  A tool to do this is available from
+ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it does'nt
+work with bt878 boards according to some reports I received.  Another
+one is available from http://www.kki.net.pl/~borgx/bTV.html.
+
+You might also dig around in the *.ini files of the Windows applications.
 You can have a look at the board to see which of the gpio pins are
 connected at all and then start trial-and-error ...
 
diff -urN linux-2.4.2-pre4/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.2-pre4/MAINTAINERS	Mon Dec  3 22:29:05 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:29:15 2001
@@ -858,6 +858,8 @@
 S:	Maintained
 
 NETWORK DEVICE DRIVERS
+P:	Andrew Morton
+M:	andrewm@uow.edu.au
 P:	Jeff Garzik
 M:	jgarzik@mandrakesoft.com
 L:	linux-net@vger.kernel.org
diff -urN linux-2.4.2-pre4/Makefile linux/Makefile
--- linux-2.4.2-pre4/Makefile	Mon Dec  3 22:29:05 2001
+++ linux/Makefile	Mon Dec  3 22:29:15 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 2
-EXTRAVERSION =-pre4
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.2-pre4/arch/cris/config.in linux/arch/cris/config.in
--- linux-2.4.2-pre4/arch/cris/config.in	Mon Dec  3 22:29:05 2001
+++ linux/arch/cris/config.in	Mon Dec  3 22:29:15 2001
@@ -14,21 +14,21 @@
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Networking support' CONFIG_NET y
-bool 'System V IPC' CONFIG_SYSVIPC y
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
 
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
 
-bool 'Use kernel gdb debugger' CONFIG_KGDB n
+bool 'Use kernel gdb debugger' CONFIG_KGDB
 
-bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG y
+bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG
 
-bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE y
+bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE
 
-bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG n
+bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG
 
 endmenu
 
diff -urN linux-2.4.2-pre4/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.4.2-pre4/arch/i386/defconfig	Mon Dec  3 22:29:05 2001
+++ linux/arch/i386/defconfig	Mon Dec  3 22:29:15 2001
@@ -634,6 +634,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
diff -urN linux-2.4.2-pre4/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- linux-2.4.2-pre4/arch/i386/kernel/head.S	Tue Nov 28 22:43:39 2000
+++ linux/arch/i386/kernel/head.S	Mon Dec  3 22:29:15 2001
@@ -34,7 +34,7 @@
 #define X86_HARD_MATH	CPU_PARAMS+6
 #define X86_CPUID	CPU_PARAMS+8
 #define X86_CAPABILITY	CPU_PARAMS+12
-#define X86_VENDOR_ID	CPU_PARAMS+16
+#define X86_VENDOR_ID	CPU_PARAMS+28
 
 /*
  * swapper_pg_dir is the main page directory, address 0x00101000
diff -urN linux-2.4.2-pre4/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.4.2-pre4/arch/i386/kernel/setup.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec  3 22:29:15 2001
@@ -1104,6 +1104,9 @@
 /*
  * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
  * order to identify the Cyrix CPU model after we're out of setup.c
+ *
+ * Actually since bugs.h doesnt even reference this perhaps someone should
+ * fix the documentation ???
  */
 unsigned char Cx86_dir0_msb __initdata = 0;
 
@@ -1129,6 +1132,8 @@
  * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
  * BIOSes for compatability with DOS games.  This makes the udelay loop
  * work correctly, and improves performance.
+ *
+ * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP
  */
 
 extern void calibrate_delay(void) __init;
@@ -1401,6 +1406,7 @@
 					wrmsr (0x1107, lo, hi);
 
 					set_bit(X86_FEATURE_CX8, &c->x86_capability);
+					set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
 
 					get_model_name(c);
 					display_cacheinfo(c);
@@ -1565,12 +1571,10 @@
 				case 4:
 					if ( c->x86 > 6 && dl ) {
 						/* P4 family */
-						if ( dl ) {
-							/* L3 cache */
-							cs = 128 << (dl-1);
-							l3 += cs;
-							break;
-						}
+						/* L3 cache */
+						cs = 128 << (dl-1);
+						l3 += cs;
+						break;
 					}
 					/* else same as 8 - fall through */
 				case 8:
@@ -1870,8 +1874,34 @@
 
 	/* Detect Cyrix with disabled CPUID */
 	if ( c->x86 == 4 && test_cyrix_52div() ) {
+		unsigned char dir0, dir1;
+		
 		strcpy(c->x86_vendor_id, "CyrixInstead");
 	        c->x86_vendor = X86_VENDOR_CYRIX;
+	        
+	        /* Actually enable cpuid on the older cyrix */
+	    
+	    	/* Retrieve CPU revisions */
+	    	
+		do_cyrix_devid(&dir0, &dir1);
+
+		dir0>>=4;		
+		
+		/* Check it is an affected model */
+		
+   	        if (dir0 == 5 || dir0 == 3)
+   	        {
+			unsigned char ccr3, ccr4;
+
+			printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
+			cli();
+			ccr3 = getCx86(CX86_CCR3);
+			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
+			ccr4 = getCx86(CX86_CCR4);
+			setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
+			setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
+			sti();
+		}
 	} else
 
 	/* Detect NexGen with old hypercode */
@@ -1914,7 +1944,6 @@
 		      (int *)&c->x86_vendor_id[4]);
 		
 		get_cpu_vendor(c);
-
 		/* Initialize the standard set of capabilities */
 		/* Note that the vendor-specific code below might override */
 
diff -urN linux-2.4.2-pre4/arch/i386/mm/extable.c linux/arch/i386/mm/extable.c
--- linux-2.4.2-pre4/arch/i386/mm/extable.c	Wed Nov 10 08:31:37 1999
+++ linux/arch/i386/mm/extable.c	Mon Dec  3 22:29:15 2001
@@ -4,6 +4,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 extern const struct exception_table_entry __start___ex_table[];
@@ -30,26 +31,32 @@
         return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
-
+	unsigned long ret = 0;
+	unsigned long flags;
+	
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
+	return ret;
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
 		if (mp->ex_table_start == NULL)
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
-		if (ret) return ret;
+		if (ret)
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -urN linux-2.4.2-pre4/arch/ia64/config.in linux/arch/ia64/config.in
--- linux-2.4.2-pre4/arch/ia64/config.in	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/config.in	Mon Dec  3 22:29:15 2001
@@ -70,7 +70,7 @@
 	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
 	  bool '    Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
 	fi
-	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM n
+	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM
 	define_bool CONFIG_DEVFS_DEBUG y
 	define_bool CONFIG_DEVFS_FS y
 	define_bool CONFIG_IA64_BRL_EMU y
@@ -79,8 +79,8 @@
 	define_bool CONFIG_SGI_IOC3_ETH y
 	define_bool CONFIG_PERCPU_IRQ y
 	define_int  CONFIG_CACHE_LINE_SHIFT 7
-	bool '  Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM y
-	bool '	Enable NUMA support' CONFIG_NUMA y
+	bool '  Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM
+	bool '	Enable NUMA support' CONFIG_NUMA
 fi
 
 define_bool CONFIG_KCORE_ELF y	# On IA-64, we always want an ELF /proc/kcore.
diff -urN linux-2.4.2-pre4/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c
--- linux-2.4.2-pre4/arch/ia64/kernel/palinfo.c	Thu Jan  4 15:25:55 2001
+++ linux/arch/ia64/kernel/palinfo.c	Mon Dec  3 22:29:15 2001
@@ -23,9 +23,6 @@
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
 
 #include <asm/pal.h>
 #include <asm/sal.h>
diff -urN linux-2.4.2-pre4/arch/ia64/sn/io/klconflib.c linux/arch/ia64/sn/io/klconflib.c
--- linux-2.4.2-pre4/arch/ia64/sn/io/klconflib.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/klconflib.c	Mon Dec  3 22:29:15 2001
@@ -511,7 +511,7 @@
 				moduleid_t kgm, pkgm;
 				int	kgs, pkgs;
 
-#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC))) && defined(BRINGUP)
+#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP)
 				printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD",
 					lb->brd_module,lb->brd_slot);
 #endif
diff -urN linux-2.4.2-pre4/arch/ia64/sn/io/klgraph_hack.c linux/arch/ia64/sn/io/klgraph_hack.c
--- linux-2.4.2-pre4/arch/ia64/sn/io/klgraph_hack.c	Thu Jan  4 13:00:15 2001
+++ linux/arch/ia64/sn/io/klgraph_hack.c	Mon Dec  3 22:29:15 2001
@@ -139,7 +139,7 @@
 	uint64_t	*tmp;
 	volatile u32	*tmp32;
 
-#ifdef 0
+#if 0
 	/* Preset some values */
 	/* Write IOERR clear to clear the CRAZY bit in the status */
 	tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff;
diff -urN linux-2.4.2-pre4/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c
--- linux-2.4.2-pre4/arch/ia64/sn/io/pcibr.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/ia64/sn/io/pcibr.c	Mon Dec  3 22:29:15 2001
@@ -3753,7 +3753,7 @@
 	 * completion interrupts will reach a CPU
 	 * after all DMA data has reached memory.
 	 * (Of course, there may be a few special
-	 * drivers/controlers that explicitly manage
+	 * drivers/controllers that explicitly manage
 	 * this ordering problem.)
 	 */
 
diff -urN linux-2.4.2-pre4/arch/ppc/8260_io/fcc_enet.c linux/arch/ppc/8260_io/fcc_enet.c
--- linux-2.4.2-pre4/arch/ppc/8260_io/fcc_enet.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/ppc/8260_io/fcc_enet.c	Mon Dec  3 22:29:15 2001
@@ -46,7 +46,7 @@
 #define TX_TIMEOUT	(2*HZ)
 
 /* The number of Tx and Rx buffers.  These are allocated from the page
- * pool.  The code may assume these are power of two, so it it best
+ * pool.  The code may assume these are power of two, so it is best
  * to keep them that size.
  * We don't need to allocate pages for the transmitter.  We just use
  * the skbuffer directly.
diff -urN linux-2.4.2-pre4/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h
--- linux-2.4.2-pre4/arch/ppc/8xx_io/commproc.h	Thu Jul 13 09:42:50 2000
+++ linux/arch/ppc/8xx_io/commproc.h	Mon Dec  3 22:29:15 2001
@@ -76,7 +76,7 @@
 	uint	cbd_bufaddr;	/* Buffer address in host memory */
 } cbd_t;
 
-#define BD_SC_EMPTY	((ushort)0x8000)	/* Recieve is empty */
+#define BD_SC_EMPTY	((ushort)0x8000)	/* Receive is empty */
 #define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */
 #define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */
 #define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */
diff -urN linux-2.4.2-pre4/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
--- linux-2.4.2-pre4/arch/ppc/8xx_io/fec.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/ppc/8xx_io/fec.c	Mon Dec  3 22:29:15 2001
@@ -73,7 +73,7 @@
 } phy_info_t;
 
 /* The number of Tx and Rx buffers.  These are allocated from the page
- * pool.  The code may assume these are power of two, so it it best
+ * pool.  The code may assume these are power of two, so it is best
  * to keep them that size.
  * We don't need to allocate pages for the transmitter.  We just use
  * the skbuffer directly.
@@ -953,7 +953,7 @@
 /* 
  * I had some nice ideas of running the MDIO faster...
  * The 971 should support 8MHz and I tried it, but things acted really
- * wierd, so 2.5 MHz ought to be enough for anyone...
+ * weird, so 2.5 MHz ought to be enough for anyone...
  */
 
 static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
diff -urN linux-2.4.2-pre4/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- linux-2.4.2-pre4/arch/ppc/amiga/amiints.c	Wed Feb  9 19:43:47 2000
+++ linux/arch/ppc/amiga/amiints.c	Mon Dec  3 22:29:15 2001
@@ -119,7 +119,7 @@
 	custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
-	/* Clear any inter-CPU interupt requests. Circumvents bug in
+	/* Clear any inter-CPU interrupt requests. Circumvents bug in
            Blizzard IPL emulation HW (or so it appears). */
 	APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
 
diff -urN linux-2.4.2-pre4/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- linux-2.4.2-pre4/arch/ppc/kernel/pmac_pic.c	Mon Jan 22 15:41:15 2001
+++ linux/arch/ppc/kernel/pmac_pic.c	Mon Dec  3 22:29:15 2001
@@ -457,7 +457,7 @@
 /*
  * These procedures are used in implementing sleep on the powerbooks.
  * sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interupts except for the nominated one.
+ * and disables all interrupts except for the nominated one.
  * sleep_restore_intrs() restores the states of all interrupt enables.
  */
 unsigned int sleep_save_mask[2];
diff -urN linux-2.4.2-pre4/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- linux-2.4.2-pre4/arch/s390x/kernel/linux32.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/s390x/kernel/linux32.c	Mon Dec  3 22:29:15 2001
@@ -1804,9 +1804,6 @@
 	return err;
 }
 
-extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
-				int options, struct rusage * ru);
-
 asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
 {
 	if (!ru)
diff -urN linux-2.4.2-pre4/arch/s390x/kernel/signal.c linux/arch/s390x/kernel/signal.c
--- linux-2.4.2-pre4/arch/s390x/kernel/signal.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/s390x/kernel/signal.c	Mon Dec  3 22:29:15 2001
@@ -53,8 +53,6 @@
 	struct ucontext uc;
 } rt_sigframe;
 
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
-			 int options, unsigned long *ru);
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
diff -urN linux-2.4.2-pre4/arch/s390x/kernel/signal32.c linux/arch/s390x/kernel/signal32.c
--- linux-2.4.2-pre4/arch/s390x/kernel/signal32.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/s390x/kernel/signal32.c	Mon Dec  3 22:29:15 2001
@@ -52,8 +52,6 @@
 	struct ucontext32 uc;
 } rt_sigframe32;
 
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
-			 int options, unsigned long *ru);
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
 int do_signal32(struct pt_regs *regs, sigset_t *oldset);
diff -urN linux-2.4.2-pre4/arch/sparc/config.in linux/arch/sparc/config.in
--- linux-2.4.2-pre4/arch/sparc/config.in	Mon Jan 22 13:30:20 2001
+++ linux/arch/sparc/config.in	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.107 2001/01/06 00:46:44 davem Exp $
+# $Id: config.in,v 1.108 2001/02/18 09:02:59 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -183,8 +183,8 @@
    mainmenu_option next_comment
    comment 'SCSI low-level drivers'
 
-   tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
-   tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+   dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+   dep_tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
    endmenu
 fi
 endmenu
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c
--- linux-2.4.2-pre4/arch/sparc/kernel/ebus.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/ebus.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.15 2000/11/08 05:06:21 davem Exp $
+/* $Id: ebus.c,v 1.16 2001/02/13 01:16:43 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- linux-2.4.2-pre4/arch/sparc/kernel/ioport.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/ioport.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.42 2000/12/05 00:56:36 anton Exp $
+/* $Id: ioport.c,v 1.44 2001/02/13 04:07:38 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -225,7 +225,7 @@
 	 * XXX Playing with implementation details here.
 	 * On sparc64 Ebus has resources with precise boundaries.
 	 * We share drivers with sparc64. Too clever drivers use
-	 * start of a resource instead of a base adress.
+	 * start of a resource instead of a base address.
 	 *
 	 * XXX-2 This may be not valid anymore, clean when
 	 * interface to sbus_ioremap() is resolved.
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- linux-2.4.2-pre4/arch/sparc/kernel/irq.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/irq.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.109 2000/08/31 10:00:39 anton Exp $
+/*  $Id: irq.c,v 1.110 2001/02/13 01:16:43 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- linux-2.4.2-pre4/arch/sparc/kernel/pcic.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/pcic.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.21 2001/01/18 00:23:00 davem Exp $
+/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- linux-2.4.2-pre4/arch/sparc/kernel/process.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/process.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.154 2000/10/05 06:12:57 anton Exp $
+/*  $Id: process.c,v 1.155 2001/02/13 01:16:43 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- linux-2.4.2-pre4/arch/sparc/kernel/ptrace.c	Mon Jun 19 17:59:38 2000
+++ linux/arch/sparc/kernel/ptrace.c	Mon Dec  3 22:29:15 2001
@@ -5,7 +5,7 @@
  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
  * and David Mosberger.
  *
- * Added Linux support -miguel (wierd, eh?, the orignal code was meant
+ * Added Linux support -miguel (weird, eh?, the orignal code was meant
  * to emulate SunOS).
  */
 
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- linux-2.4.2-pre4/arch/sparc/kernel/setup.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/setup.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.122 2001/01/01 01:46:15 davem Exp $
+/*  $Id: setup.c,v 1.123 2001/02/13 01:16:43 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c
--- linux-2.4.2-pre4/arch/sparc/kernel/sun4d_irq.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/sun4d_irq.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: sun4d_irq.c,v 1.26 2000/07/26 01:04:03 davem Exp $
+/*  $Id: sun4d_irq.c,v 1.27 2001/02/13 01:16:43 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *			SS1000/SC2000 interrupt handling.
  *
diff -urN linux-2.4.2-pre4/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.2-pre4/arch/sparc/kernel/sys_sunos.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.131 2001/01/24 21:05:12 davem Exp $
+/* $Id: sys_sunos.c,v 1.132 2001/02/13 01:16:43 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c
--- linux-2.4.2-pre4/arch/sparc/mm/io-unit.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/mm/io-unit.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.22 2000/08/09 00:00:15 davem Exp $
+/* $Id: io-unit.c,v 1.23 2001/02/13 01:16:43 davem Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
diff -urN linux-2.4.2-pre4/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c
--- linux-2.4.2-pre4/arch/sparc/mm/iommu.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/mm/iommu.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.20 2000/08/09 00:00:15 davem Exp $
+/* $Id: iommu.c,v 1.21 2001/02/13 01:16:43 davem Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- linux-2.4.2-pre4/arch/sparc/mm/srmmu.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc/mm/srmmu.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.225 2000/11/30 08:37:31 anton Exp $
+/* $Id: srmmu.c,v 1.226 2001/02/13 01:16:44 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- linux-2.4.2-pre4/arch/sparc/mm/sun4c.c	Mon Dec 11 12:37:03 2000
+++ linux/arch/sparc/mm/sun4c.c	Mon Dec  3 22:29:15 2001
@@ -353,7 +353,7 @@
 			break;
 
 		default:
-			prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
+			prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
 			prom_halt();
 		};
 	} else {
diff -urN linux-2.4.2-pre4/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.4.2-pre4/arch/sparc64/config.in	Mon Jan 22 13:30:20 2001
+++ linux/arch/sparc64/config.in	Mon Dec  3 22:29:15 2001
@@ -161,15 +161,15 @@
    mainmenu_option next_comment
    comment 'SCSI low-level drivers'
 
-   tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
-   tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+   dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+   dep_tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
 
    if [ "$CONFIG_PCI" != "n" ]; then
       dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
       if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
 	 bool '  Enable tagged command queueing (TCQ) by default' CONFIG_AIC7XXX_TAGGED_QUEUEING
 	 int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
-  	 bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+  	 bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
 	 int  '  Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
       fi
       dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
@@ -196,6 +196,8 @@
    endmenu
 fi
 endmenu
+
+source drivers/message/fusion/Config.in
 
 source drivers/fc4/Config.in
 
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/ebus.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/ebus.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.53 2000/11/08 05:08:23 davem Exp $
+/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.106 2001/01/30 01:04:28 davem Exp $
+/* $Id: ioctl32.c,v 1.107 2001/02/13 01:16:44 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/irq.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/irq.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.94 2000/09/21 06:27:10 anton Exp $
+/* $Id: irq.c,v 1.95 2001/02/13 01:16:44 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/pci_common.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.12 2000/05/01 06:32:49 davem Exp $
+/* $Id: pci_common.c,v 1.13 2001/02/13 01:16:44 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/pci_psycho.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.18 2001/01/11 16:26:45 davem Exp $
+/* $Id: pci_psycho.c,v 1.19 2001/02/13 01:16:44 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/pci_sabre.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.22 2001/01/16 13:03:48 anton Exp $
+/* $Id: pci_sabre.c,v 1.23 2001/02/13 01:16:44 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/pci_schizo.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.2 2001/01/12 02:43:30 davem Exp $
+/* $Id: pci_schizo.c,v 1.3 2001/02/13 01:16:44 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/process.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/process.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.113 2000/11/08 08:14:58 davem Exp $
+/*  $Id: process.c,v 1.114 2001/02/13 01:16:44 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/ptrace.c	Mon Jun 19 17:59:38 2000
+++ linux/arch/sparc64/kernel/ptrace.c	Mon Dec  3 22:29:15 2001
@@ -6,7 +6,7 @@
  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
  * and David Mosberger.
  *
- * Added Linux support -miguel (wierd, eh?, the orignal code was meant
+ * Added Linux support -miguel (weird, eh?, the orignal code was meant
  * to emulate SunOS).
  */
 
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/sbus.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/sbus.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.12 2000/09/21 06:25:14 anton Exp $
+/* $Id: sbus.c,v 1.13 2001/02/13 01:16:44 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/setup.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/setup.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.58 2001/01/01 01:46:15 davem Exp $
+/*  $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/starfire.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/starfire.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: starfire.c,v 1.8 2000/10/27 18:36:47 anton Exp $
+/* $Id: starfire.c,v 1.9 2001/02/13 01:16:44 davem Exp $
  * starfire.c: Starfire/E10000 support.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/sys_sparc.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/sys_sparc.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.47 2000/11/29 05:56:12 anton Exp $
+/* $Id: sys_sparc.c,v 1.48 2001/02/13 01:16:44 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/sys_sparc32.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.172 2001/01/24 21:05:13 davem Exp $
+/* $Id: sys_sparc32.c,v 1.173 2001/02/13 01:16:44 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -urN linux-2.4.2-pre4/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.2-pre4/arch/sparc64/kernel/sys_sunos32.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.56 2001/01/04 05:35:48 davem Exp $
+/* $Id: sys_sunos32.c,v 1.57 2001/02/13 01:16:44 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- linux-2.4.2-pre4/arch/sparc64/mm/init.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/mm/init.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.161 2000/12/09 20:16:58 davem Exp $
+/*  $Id: init.c,v 1.162 2001/02/13 01:16:44 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- linux-2.4.2-pre4/arch/sparc64/mm/modutil.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/mm/modutil.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/*  $Id: modutil.c,v 1.6 2000/06/26 23:20:24 davem Exp $
+/*  $Id: modutil.c,v 1.7 2001/02/13 01:16:44 davem Exp $
  *  arch/sparc64/mm/modutil.c
  *
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -urN linux-2.4.2-pre4/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- linux-2.4.2-pre4/arch/sparc64/solaris/fs.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/solaris/fs.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.23 2000/08/29 07:01:54 davem Exp $
+/* $Id: fs.c,v 1.24 2001/02/13 01:16:44 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -urN linux-2.4.2-pre4/arch/sparc64/solaris/socket.c linux/arch/sparc64/solaris/socket.c
--- linux-2.4.2-pre4/arch/sparc64/solaris/socket.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/solaris/socket.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: socket.c,v 1.4 2000/11/18 02:11:00 davem Exp $
+/* $Id: socket.c,v 1.5 2001/02/13 01:16:44 davem Exp $
  * socket.c: Socket syscall emulation for Solaris 2.6+
  *
  * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- linux-2.4.2-pre4/arch/sparc64/solaris/socksys.c	Mon Dec  3 22:29:05 2001
+++ linux/arch/sparc64/solaris/socksys.c	Mon Dec  3 22:29:15 2001
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.17 2000/10/19 00:49:53 davem Exp $
+/* $Id: socksys.c,v 1.18 2001/02/13 01:16:44 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -urN linux-2.4.2-pre4/drivers/acpi/acpi_ksyms.c linux/drivers/acpi/acpi_ksyms.c
--- linux-2.4.2-pre4/drivers/acpi/acpi_ksyms.c	Mon Dec  3 22:29:05 2001
+++ linux/drivers/acpi/acpi_ksyms.c	Mon Jan 29 10:15:58 2001
@@ -18,7 +18,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
diff -urN linux-2.4.2-pre4/drivers/acpi/include/aclinux.h linux/drivers/acpi/include/aclinux.h
--- linux-2.4.2-pre4/drivers/acpi/include/aclinux.h	Mon Dec  3 22:29:05 2001
+++ linux/drivers/acpi/include/aclinux.h	Mon Dec  3 22:29:15 2001
@@ -28,7 +28,6 @@
 
 #define ACPI_OS_NAME                "Linux"
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
diff -urN linux-2.4.2-pre4/drivers/atm/Config.in linux/drivers/atm/Config.in
--- linux-2.4.2-pre4/drivers/atm/Config.in	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/Config.in	Mon Dec  3 22:29:15 2001
@@ -56,7 +56,7 @@
   tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE
   if [ "$CONFIG_ATM_FORE200E_MAYBE" != "n" ]; then
     if [ "$CONFIG_PCI" = "y" ]; then
-      bool '  PCA-200E support' CONFIG_ATM_FORE200E_PCA y
+      bool '  PCA-200E support' CONFIG_ATM_FORE200E_PCA
       if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then
 	bool '   Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
         if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then
@@ -65,7 +65,7 @@
       fi
     fi
     if [ "$CONFIG_SBUS" = "y" ]; then
-      bool '  SBA-200E support' CONFIG_ATM_FORE200E_SBA y
+      bool '  SBA-200E support' CONFIG_ATM_FORE200E_SBA
       if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then
         bool '   Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
         if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then
diff -urN linux-2.4.2-pre4/drivers/atm/firestream.c linux/drivers/atm/firestream.c
--- linux-2.4.2-pre4/drivers/atm/firestream.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/firestream.c	Mon Dec  3 22:29:15 2001
@@ -1441,7 +1441,7 @@
 
 
 /* Check if this gets going again if a pool ever runs out.  -- Yes, it
-   does. I've seen "recieve abort: no buffers" and things started
+   does. I've seen "receive abort: no buffers" and things started
    working again after that...  -- REW */
 
 static void top_off_fp (struct fs_dev *dev, struct freepool *fp, int gfp_flags)
diff -urN linux-2.4.2-pre4/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- linux-2.4.2-pre4/drivers/atm/nicstar.c	Mon Dec  3 22:29:05 2001
+++ linux/drivers/atm/nicstar.c	Mon Dec  3 22:29:15 2001
@@ -1360,7 +1360,7 @@
       printk("nicstar%d: Raw cell received and no support yet...\n",
              card->index);
 #endif /* RCQ_SUPPORT */
-      /* NOTE: the following procedure may keep a raw cell pending untill the
+      /* NOTE: the following procedure may keep a raw cell pending until the
                next interrupt. As this preliminary support is only meant to
                avoid buffer leakage, this is not an issue. */
       while (readl(card->membase + RAWCT) != card->rawch)
diff -urN linux-2.4.2-pre4/drivers/atm/nicstar.h linux/drivers/atm/nicstar.h
--- linux-2.4.2-pre4/drivers/atm/nicstar.h	Mon Dec 11 13:22:02 2000
+++ linux/drivers/atm/nicstar.h	Mon Dec  3 22:29:15 2001
@@ -613,7 +613,7 @@
 #define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_48
 #elif (NS_SMBUFSIZE == 96)
 #define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_96
-#eliif (NS_SMBUFSIZE == 240)
+#elif (NS_SMBUFSIZE == 240)
 #define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_240
 #elif (NS_SMBUFSIZE == 2048)
 #define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_2048
diff -urN linux-2.4.2-pre4/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- linux-2.4.2-pre4/drivers/block/DAC960.c	Mon Dec  3 22:29:05 2001
+++ linux/drivers/block/DAC960.c	Mon Dec  3 22:29:15 2001
@@ -2,7 +2,7 @@
 
   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.4.9"
-#define DAC960_DriverDate			"7 September 2000"
+#define DAC960_DriverVersion			"2.4.10"
+#define DAC960_DriverDate			"1 February 2001"
 
 
 #include <linux/version.h>
@@ -51,7 +51,7 @@
 */
 
 static int
-  DAC960_ControllerCount;
+  DAC960_ControllerCount =			0;
 
 
 /*
@@ -60,7 +60,7 @@
 */
 
 static int
-  DAC960_ActiveControllerCount;
+  DAC960_ActiveControllerCount =		0;
 
 
 /*
@@ -69,7 +69,7 @@
 */
 
 static DAC960_Controller_T
-  *DAC960_Controllers[DAC960_MaxControllers];
+  *DAC960_Controllers[DAC960_MaxControllers] =	{ NULL };
 
 
 /*
@@ -110,7 +110,7 @@
   DAC960_Announce("***** DAC960 RAID Driver Version "
 		  DAC960_DriverVersion " of "
 		  DAC960_DriverDate " *****\n", Controller);
-  DAC960_Announce("Copyright 1998-2000 by Leonard N. Zubkoff "
+  DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff "
 		  "<lnz@dandelion.com>\n", Controller);
 }
 
@@ -511,7 +511,7 @@
   DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3.CommandOpcode = CommandOpcode;
-  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
+  CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer);
   DAC960_ExecuteCommand(Command);
   CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
@@ -539,7 +539,7 @@
   CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
-  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
+  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer);
   DAC960_ExecuteCommand(Command);
   CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
@@ -573,7 +573,7 @@
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentByteCount =
@@ -612,7 +612,7 @@
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentByteCount =
@@ -655,7 +655,7 @@
   CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 				   .ScatterGatherSegments[0]
 				   .SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 				   .ScatterGatherSegments[0]
 				   .SegmentByteCount =
@@ -700,7 +700,7 @@
   CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 				    .ScatterGatherSegments[0]
 				    .SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 				    .ScatterGatherSegments[0]
 				    .SegmentByteCount =
@@ -816,9 +816,9 @@
   CommandMailbox.TypeX.CommandIdentifier = 0;
   CommandMailbox.TypeX.CommandOpcode2 = 0x14;
   CommandMailbox.TypeX.CommandMailboxesBusAddress =
-    Virtual_to_Bus(Controller->V1.FirstCommandMailbox);
+    Virtual_to_Bus32(Controller->V1.FirstCommandMailbox);
   CommandMailbox.TypeX.StatusMailboxesBusAddress =
-    Virtual_to_Bus(Controller->V1.FirstStatusMailbox);
+    Virtual_to_Bus32(Controller->V1.FirstStatusMailbox);
   for (i = 0; i < 2; i++)
     switch (Controller->HardwareType)
       {
@@ -940,11 +940,11 @@
   CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox;
   CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1;
   CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress =
-    Virtual_to_Bus(Controller->V2.HealthStatusBuffer);
+    Virtual_to_Bus64(Controller->V2.HealthStatusBuffer);
   CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress =
-    Virtual_to_Bus(Controller->V2.FirstCommandMailbox);
+    Virtual_to_Bus64(Controller->V2.FirstCommandMailbox);
   CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress =
-    Virtual_to_Bus(Controller->V2.FirstStatusMailbox);
+    Virtual_to_Bus64(Controller->V2.FirstStatusMailbox);
   switch (Controller->HardwareType)
     {
     case DAC960_BA_Controller:
@@ -1334,7 +1334,7 @@
 	  Command->CommandType = DAC960_ImmediateCommand;
 	  Command->Semaphore = Semaphore;
 	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
-	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
+	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB);
 	  DCDB->Channel = Channel;
 	  DCDB->TargetID = TargetID;
 	  DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -1343,7 +1343,7 @@
 	  DCDB->NoAutomaticRequestSense = false;
 	  DCDB->DisconnectPermitted = true;
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	  DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	  DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData);
 	  DCDB->CDBLength = 6;
 	  DCDB->TransferLengthHigh4 = 0;
 	  DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -1370,7 +1370,7 @@
 	  Command->Semaphore = Semaphore;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	  DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	  DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
 	  DCDB->SenseLength = sizeof(DCDB->SenseData);
 	  DCDB->CDB[0] = 0x12; /* INQUIRY */
 	  DCDB->CDB[1] = 1; /* EVPD = 1 */
@@ -1461,7 +1461,7 @@
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentDataPointer =
-	Virtual_to_Bus(InquiryUnitSerialNumber);
+	Virtual_to_Bus64(InquiryUnitSerialNumber);
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentByteCount =
@@ -1864,7 +1864,7 @@
   int TotalSegments = Request->nr_segments + NextRequest->nr_segments;
   if (Request->bhtail->b_data + Request->bhtail->b_size
       == NextRequest->bh->b_data)
-      TotalSegments--;
+    TotalSegments--;
   if (TotalSegments > MaxSegments ||
       TotalSegments > Controller->DriverScatterGatherLimit)
     return false;
@@ -2602,7 +2602,8 @@
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(Command->RequestBuffer);
+      CommandMailbox->Type5.BusAddress =
+	Virtual_to_Bus32(Command->RequestBuffer);
     }
   else
     {
@@ -2620,7 +2621,7 @@
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus32(ScatterGatherList);
       CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
       while (BufferHeader != NULL)
 	{
@@ -2633,7 +2634,7 @@
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
-		Virtual_to_Bus(BufferHeader->b_data);
+		Virtual_to_Bus32(BufferHeader->b_data);
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
@@ -2665,7 +2666,7 @@
   CommandMailbox->SCSI_10.DataTransferSize =
     Command->BlockCount << DAC960_BlockSizeBits;
   CommandMailbox->SCSI_10.RequestSenseBusAddress =
-    Virtual_to_Bus(&Command->V2.RequestSense);
+    Virtual_to_Bus64(&Command->V2.RequestSense);
   CommandMailbox->SCSI_10.PhysicalDevice =
     Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber];
   CommandMailbox->SCSI_10.RequestSenseSize =
@@ -2684,7 +2685,7 @@
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentDataPointer =
-	Virtual_to_Bus(Command->RequestBuffer);
+	Virtual_to_Bus64(Command->RequestBuffer);
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentByteCount =
@@ -2706,7 +2707,7 @@
 	    Command->SegmentCount;
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			 .ExtendedScatterGather.ScatterGatherList0Address =
-	    Virtual_to_Bus(ScatterGatherList);
+	    Virtual_to_Bus64(ScatterGatherList);
 	}
       else
 	ScatterGatherList =
@@ -2723,7 +2724,7 @@
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
-		Virtual_to_Bus(BufferHeader->b_data);
+		Virtual_to_Bus64(BufferHeader->b_data);
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
@@ -2950,7 +2951,7 @@
 	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(BufferHeader->b_data);
+	    Virtual_to_Bus32(BufferHeader->b_data);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3006,7 +3007,7 @@
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
 	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(NextBufferHeader->b_data);
+	    Virtual_to_Bus32(NextBufferHeader->b_data);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3019,11 +3020,13 @@
 	{
 	  if (CommandOpcode == DAC960_V1_Enquiry)
 	    memcpy(&Controller->V1.NewEnquiry,
-		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   Bus32_to_Virtual(Command->V1.CommandMailbox
+					       .Type3.BusAddress),
 		   sizeof(DAC960_V1_Enquiry_T));
 	  else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
 	    memcpy(&Controller->V1.RebuildProgress,
-		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   Bus32_to_Virtual(Command->V1.CommandMailbox
+					       .Type3.BusAddress),
 		   sizeof(DAC960_V1_RebuildProgress_T));
 	}
       if (CommandOpcode == DAC960_V1_Enquiry &&
@@ -3037,18 +3040,25 @@
 	    NewEnquiry->CriticalLogicalDriveCount;
 	  if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount)
 	    {
-	      int LogicalDriveNumber = Controller->LogicalDriveCount;
-	      while (LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
-		{
-		  DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
-				  "Now Exists\n", Controller,
-				  LogicalDriveNumber,
-				  Controller->ControllerNumber,
-				  LogicalDriveNumber);
-		  LogicalDriveNumber++;
-		}
-	      Controller->LogicalDriveCount = LogicalDriveNumber;
+	      int LogicalDriveNumber = Controller->LogicalDriveCount - 1;
+	      while (++LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"Now Exists\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber);
+	    }
+	  if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
+	    {
+	      int LogicalDriveNumber = NewEnquiry->NumberOfLogicalDrives - 1;
+	      while (++LogicalDriveNumber < Controller->LogicalDriveCount)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"No Longer Exists\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber);
 	    }
+	  Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
 	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -3073,8 +3083,7 @@
 		NewEnquiry->EventLogSequenceNumber;
 	      Controller->V1.NeedErrorTableInformation = true;
 	      Controller->V1.NeedDeviceStateInformation = true;
-	      Controller->V1.DeviceStateChannel = 0;
-	      Controller->V1.DeviceStateTargetID = -1;
+	      Controller->V1.StartDeviceStateScan = true;
 	      Controller->SecondaryMonitoringTime = jiffies;
 	    }
 	  if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
@@ -3133,7 +3142,7 @@
 	      Controller->V1.RebuildFlagPending)
 	    {
 	      DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *)
-		Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
+		Bus32_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
 	      Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag;
 	      Controller->V1.RebuildFlagPending = false;
 	    }
@@ -3279,6 +3288,9 @@
 	    {
 	      Controller->V1.NeedDeviceInquiryInformation = true;
 	      Controller->V1.NeedDeviceSerialNumberInformation = true;
+	      Controller->V1.DeviceResetCount
+			     [Controller->V1.DeviceStateChannel]
+			     [Controller->V1.DeviceStateTargetID] = 0;
 	    }
 	  memcpy(OldDeviceState, NewDeviceState,
 		 sizeof(DAC960_V1_DeviceState_T));
@@ -3418,7 +3430,7 @@
 	  Command->V1.CommandMailbox.Type3E.SequenceNumber =
 	    Controller->V1.OldEventLogSequenceNumber;
 	  Command->V1.CommandMailbox.Type3E.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.EventLogEntry);
+	    Virtual_to_Bus32(&Controller->V1.EventLogEntry);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3428,7 +3440,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetErrorTable;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.NewErrorTable);
+	    Virtual_to_Bus32(&Controller->V1.NewErrorTable);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3439,7 +3451,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetRebuildProgress;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3455,7 +3467,7 @@
 	      InquiryStandardData->PeripheralDeviceType = 0x1F;
 	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DCDB);
+		Virtual_to_Bus32(DCDB);
 	      DCDB->Channel = Controller->V1.DeviceStateChannel;
 	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
 	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -3464,7 +3476,7 @@
 	      DCDB->NoAutomaticRequestSense = false;
 	      DCDB->DisconnectPermitted = true;
 	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	      DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData);
 	      DCDB->CDBLength = 6;
 	      DCDB->TransferLengthHigh4 = 0;
 	      DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -3488,7 +3500,7 @@
 	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
 	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DCDB);
+		Virtual_to_Bus32(DCDB);
 	      DCDB->Channel = Controller->V1.DeviceStateChannel;
 	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
 	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -3498,7 +3510,7 @@
 	      DCDB->DisconnectPermitted = true;
 	      DCDB->TransferLength =
 		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	      DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
 	      DCDB->CDBLength = 6;
 	      DCDB->TransferLengthHigh4 = 0;
 	      DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -3512,35 +3524,31 @@
 	      Controller->V1.NeedDeviceSerialNumberInformation = false;
 	      return;
 	    }
-	  if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+	  if (Controller->V1.StartDeviceStateScan)
+	    {
+	      Controller->V1.DeviceStateChannel = 0;
+	      Controller->V1.DeviceStateTargetID = 0;
+	      Controller->V1.StartDeviceStateScan = false;
+	    }
+	  else if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
 	    {
 	      Controller->V1.DeviceStateChannel++;
 	      Controller->V1.DeviceStateTargetID = 0;
 	    }
-	  while (Controller->V1.DeviceStateChannel < Controller->Channels)
+	  if (Controller->V1.DeviceStateChannel < Controller->Channels)
 	    {
-	      DAC960_V1_DeviceState_T *OldDeviceState =
-		&Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
-					   [Controller->V1.DeviceStateTargetID];
-	      if (OldDeviceState->Present &&
-		  OldDeviceState->DeviceType == DAC960_V1_DiskType)
-		{
-		  Command->V1.CommandMailbox.Type3D.CommandOpcode =
-		    DAC960_V1_GetDeviceState;
-		  Command->V1.CommandMailbox.Type3D.Channel =
-		    Controller->V1.DeviceStateChannel;
-		  Command->V1.CommandMailbox.Type3D.TargetID =
-		    Controller->V1.DeviceStateTargetID;
-		  Command->V1.CommandMailbox.Type3D.BusAddress =
-		    Virtual_to_Bus(&Controller->V1.NewDeviceState);
-		  DAC960_QueueCommand(Command);
-		  return;
-		}
-	      if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
-		{
-		  Controller->V1.DeviceStateChannel++;
-		  Controller->V1.DeviceStateTargetID = 0;
-		}
+	      Controller->V1.NewDeviceState.DeviceState =
+		DAC960_V1_Device_Dead;
+	      Command->V1.CommandMailbox.Type3D.CommandOpcode =
+		DAC960_V1_GetDeviceState;
+	      Command->V1.CommandMailbox.Type3D.Channel =
+		Controller->V1.DeviceStateChannel;
+	      Command->V1.CommandMailbox.Type3D.TargetID =
+		Controller->V1.DeviceStateTargetID;
+	      Command->V1.CommandMailbox.Type3D.BusAddress =
+		Virtual_to_Bus32(&Controller->V1.NewDeviceState);
+	      DAC960_QueueCommand(Command);
+	      return;
 	    }
 	  Controller->V1.NeedDeviceStateInformation = false;
 	}
@@ -3550,7 +3558,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetLogicalDriveInformation;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.NewLogicalDriveInformation);
+	    Virtual_to_Bus32(&Controller->V1.NewLogicalDriveInformation);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3560,7 +3568,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetRebuildProgress;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3570,7 +3578,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_RebuildStat;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3948,7 +3956,7 @@
 	    Command->BlockCount << DAC960_BlockSizeBits;
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0].SegmentDataPointer =
-	    Virtual_to_Bus(BufferHeader->b_data);
+	    Virtual_to_Bus64(BufferHeader->b_data);
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0].SegmentByteCount =
 	    CommandMailbox->SCSI_10.DataTransferSize;
@@ -4009,7 +4017,7 @@
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0]
 				 .SegmentDataPointer =
-	    Virtual_to_Bus(NextBufferHeader->b_data);
+	    Virtual_to_Bus64(NextBufferHeader->b_data);
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0]
 				 .SegmentByteCount =
@@ -4035,12 +4043,9 @@
 	  Controller->LogicalDriveCount =
 	    NewControllerInfo->LogicalDevicesPresent;
 	  Controller->V2.NeedLogicalDeviceInformation = true;
-	  Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber = 0;
 	  Controller->V2.NeedPhysicalDeviceInformation = true;
-	  Controller->V2.PhysicalDeviceIndex = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	  Controller->V2.StartLogicalDeviceInformationScan = true;
+	  Controller->V2.StartPhysicalDeviceInformationScan = true;
 	  Controller->MonitoringAlertMode =
 	    (NewControllerInfo->LogicalDevicesCritical > 0 ||
 	     NewControllerInfo->LogicalDevicesOffline > 0 ||
@@ -4063,7 +4068,49 @@
 	  unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex;
 	  DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
 	    Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
-	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+	    Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+	  unsigned int DeviceIndex;
+	  while (PhysicalDeviceInfo != NULL &&
+		 (NewPhysicalDeviceInfo->Channel >
+		  PhysicalDeviceInfo->Channel ||
+		  (NewPhysicalDeviceInfo->Channel ==
+		   PhysicalDeviceInfo->Channel &&
+		   (NewPhysicalDeviceInfo->TargetID >
+		    PhysicalDeviceInfo->TargetID ||
+		   (NewPhysicalDeviceInfo->TargetID ==
+		    PhysicalDeviceInfo->TargetID &&
+		    NewPhysicalDeviceInfo->LogicalUnit >
+		    PhysicalDeviceInfo->LogicalUnit)))))
+	    {
+	      DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
+			      Controller,
+			      PhysicalDeviceInfo->Channel,
+			      PhysicalDeviceInfo->TargetID);
+	      Controller->V2.PhysicalDeviceInformation
+			     [PhysicalDeviceIndex] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber
+			     [PhysicalDeviceIndex] = NULL;
+	      kfree(PhysicalDeviceInfo);
+	      kfree(InquiryUnitSerialNumber);
+	      for (DeviceIndex = PhysicalDeviceIndex;
+		   DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
+		   DeviceIndex++)
+		{
+		  Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
+		    Controller->V2.PhysicalDeviceInformation[DeviceIndex+1];
+		  Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
+		    Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1];
+		}
+	      Controller->V2.PhysicalDeviceInformation
+			     [DAC960_V2_MaxPhysicalDevices-1] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber
+			     [DAC960_V2_MaxPhysicalDevices-1] = NULL;
+	      PhysicalDeviceInfo =
+		Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+	      InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+	    }
 	  if (PhysicalDeviceInfo == NULL ||
 	      (NewPhysicalDeviceInfo->Channel !=
 	       PhysicalDeviceInfo->Channel) ||
@@ -4072,14 +4119,14 @@
 	      (NewPhysicalDeviceInfo->LogicalUnit !=
 	       PhysicalDeviceInfo->LogicalUnit))
 	    {
-	      unsigned int DeviceIndex;
 	      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
 		kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
 	      InquiryUnitSerialNumber =
 		(DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
 		  kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
 			  GFP_ATOMIC);
-	      if (InquiryUnitSerialNumber == NULL)
+	      if (InquiryUnitSerialNumber == NULL &&
+		  PhysicalDeviceInfo != NULL)
 		{
 		  kfree(PhysicalDeviceInfo);
 		  PhysicalDeviceInfo = NULL;
@@ -4092,21 +4139,6 @@
 			       ? "" : " - Allocation Failed"));
 	      if (PhysicalDeviceInfo != NULL)
 		{
-		  for (DeviceIndex = PhysicalDeviceIndex;
-		       DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
-		       DeviceIndex++)
-		    {
-		      Controller->V2.PhysicalDeviceInformation[DeviceIndex+1] =
-			Controller->V2.PhysicalDeviceInformation[DeviceIndex];
-		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1] =
-			Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
-		      Controller->V2.PhysicalDeviceInformation
-				     [PhysicalDeviceIndex] =
-			PhysicalDeviceInfo;
-		      Controller->V2.InquiryUnitSerialNumber
-				     [PhysicalDeviceIndex] =
-			InquiryUnitSerialNumber;
-		    }
 		  memset(PhysicalDeviceInfo, 0,
 			 sizeof(DAC960_V2_PhysicalDeviceInfo_T));
 		  PhysicalDeviceInfo->PhysicalDeviceState =
@@ -4114,6 +4146,21 @@
 		  memset(InquiryUnitSerialNumber, 0,
 			 sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
 		  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+		  for (DeviceIndex = DAC960_V2_MaxPhysicalDevices - 1;
+		       DeviceIndex > PhysicalDeviceIndex;
+		       DeviceIndex--)
+		    {
+		      Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
+			Controller->V2.PhysicalDeviceInformation[DeviceIndex-1];
+		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
+			Controller->V2.InquiryUnitSerialNumber[DeviceIndex-1];
+		    }
+		  Controller->V2.PhysicalDeviceInformation
+				 [PhysicalDeviceIndex] =
+		    PhysicalDeviceInfo;
+		  Controller->V2.InquiryUnitSerialNumber
+				 [PhysicalDeviceIndex] =
+		    InquiryUnitSerialNumber;
 		  Controller->V2.NeedDeviceSerialNumberInformation = true;
 		}
 	    }
@@ -4176,8 +4223,10 @@
 				  NewPhysicalDeviceInfo
 				  ->PredictedFailuresDetected);
 		}
-	      if (PhysicalDeviceInfo->PhysicalDeviceState
-		  == DAC960_V2_Device_Dead &&
+	      if ((PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_Dead ||
+		   PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_InvalidState) &&
 		  NewPhysicalDeviceInfo->PhysicalDeviceState
 		  != DAC960_V2_Device_Dead)
 		Controller->V2.NeedDeviceSerialNumberInformation = true;
@@ -4188,7 +4237,28 @@
 	  Controller->V2.PhysicalDeviceIndex++;
 	}
       else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
-	Controller->V2.NeedPhysicalDeviceInformation = false;
+	{
+	  unsigned int DeviceIndex;
+	  for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
+	       DeviceIndex < DAC960_V2_MaxPhysicalDevices;
+	       DeviceIndex++)
+	    {
+	      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+		Controller->V2.PhysicalDeviceInformation[DeviceIndex];
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
+	      if (PhysicalDeviceInfo == NULL) break;
+	      DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
+			      Controller,
+			      PhysicalDeviceInfo->Channel,
+			      PhysicalDeviceInfo->TargetID);
+	      Controller->V2.PhysicalDeviceInformation[DeviceIndex] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = NULL;
+	      kfree(PhysicalDeviceInfo);
+	      kfree(InquiryUnitSerialNumber);
+	    }
+	  Controller->V2.NeedPhysicalDeviceInformation = false;
+	}
       else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
 	       CommandStatus == DAC960_V2_NormalCompletion)
 	{
@@ -4295,13 +4365,50 @@
 					 NewLogicalDeviceInfo
 					 ->PatrolOperationBlockNumber,
 					 LogicalDeviceSize);
+	      if (LogicalDeviceInfo->BackgroundInitializationInProgress &&
+		  !NewLogicalDeviceInfo->BackgroundInitializationInProgress)
+		DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) "
+				"Background Initialization %s\n",
+				Controller,
+				LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				(NewLogicalDeviceInfo->LogicalDeviceControl
+						      .LogicalDeviceInitialized
+				 ? "Completed" : "Failed"));
 	      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
 		     sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
+	  Controller->V2.LogicalDriveFoundDuringScan
+			 [LogicalDeviceNumber] = true;
 	  NewLogicalDeviceInfo->LogicalDeviceNumber++;
 	}
       else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
-	Controller->V2.NeedLogicalDeviceInformation = false;
+	{
+	  int LogicalDriveNumber;
+	  for (LogicalDriveNumber = 0;
+	       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	       LogicalDriveNumber++)
+	    {
+	      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+		Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	      if (LogicalDeviceInfo == NULL ||
+		  Controller->V2.LogicalDriveFoundDuringScan
+				 [LogicalDriveNumber])
+		continue;
+	      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+			      "No Longer Exists\n", Controller,
+			      LogicalDriveNumber,
+			      Controller->ControllerNumber,
+			      LogicalDriveNumber);
+	      Controller->V2.LogicalDeviceInformation
+			     [LogicalDriveNumber] = NULL;
+	      kfree(LogicalDeviceInfo);
+	      Controller->LogicalDriveInitiallyAccessible
+			  [LogicalDriveNumber] = false;
+	    }
+	  Controller->V2.NeedLogicalDeviceInformation = false;
+	}
       if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
 	  - Controller->V2.NextEventSequenceNumber > 0)
 	{
@@ -4317,7 +4424,7 @@
 	  CommandMailbox->GetEvent.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.Event);
+	    Virtual_to_Bus64(&Controller->V2.Event);
 	  CommandMailbox->GetEvent.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -4354,7 +4461,7 @@
 	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				     .ScatterGatherSegments[0]
 				     .SegmentDataPointer =
-		Virtual_to_Bus(InquiryUnitSerialNumber);
+		Virtual_to_Bus64(InquiryUnitSerialNumber);
 	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				     .ScatterGatherSegments[0]
 				     .SegmentByteCount =
@@ -4363,6 +4470,14 @@
 	      Controller->V2.NeedDeviceSerialNumberInformation = false;
 	      return;
 	    }
+	  if (Controller->V2.StartPhysicalDeviceInformationScan)
+	    {
+	      Controller->V2.PhysicalDeviceIndex = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	      Controller->V2.StartPhysicalDeviceInformationScan = false;
+	    }
 	  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
 	    sizeof(DAC960_V2_PhysicalDeviceInfo_T);
@@ -4377,7 +4492,7 @@
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 					    .ScatterGatherSegments[0]
 					    .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.NewPhysicalDeviceInformation);
+	    Virtual_to_Bus64(&Controller->V2.NewPhysicalDeviceInformation);
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 					    .ScatterGatherSegments[0]
 					    .SegmentByteCount =
@@ -4387,6 +4502,18 @@
 	}
       if (Controller->V2.NeedLogicalDeviceInformation)
 	{
+	  if (Controller->V2.StartLogicalDeviceInformationScan)
+	    {
+	      int LogicalDriveNumber;
+	      for (LogicalDriveNumber = 0;
+		   LogicalDriveNumber < DAC960_MaxLogicalDrives;
+		   LogicalDriveNumber++)
+		Controller->V2.LogicalDriveFoundDuringScan
+			       [LogicalDriveNumber] = false;
+	      Controller->V2.NewLogicalDeviceInformation
+			    .LogicalDeviceNumber = 0;
+	      Controller->V2.StartLogicalDeviceInformationScan = false;
+	    }
 	  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
 	  CommandMailbox->LogicalDeviceInfo.DataTransferSize =
 	    sizeof(DAC960_V2_LogicalDeviceInfo_T);
@@ -4397,7 +4524,7 @@
 	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 					   .ScatterGatherSegments[0]
 					   .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.NewLogicalDeviceInformation);
+	    Virtual_to_Bus64(&Controller->V2.NewLogicalDeviceInformation);
 	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 					   .ScatterGatherSegments[0]
 					   .SegmentByteCount =
@@ -4695,7 +4822,8 @@
   DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_MonitoringCommand;
   CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry;
-  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(&Controller->V1.NewEnquiry);
+  CommandMailbox->Type3.BusAddress =
+    Virtual_to_Bus32(&Controller->V1.NewEnquiry);
   DAC960_QueueCommand(Command);
 }
 
@@ -4723,7 +4851,7 @@
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentDataPointer =
-    Virtual_to_Bus(&Controller->V2.NewControllerInformation);
+    Virtual_to_Bus64(&Controller->V2.NewControllerInformation);
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentByteCount =
@@ -4766,6 +4894,28 @@
 	&Controller->V2.ControllerInformation;
       unsigned int StatusChangeCounter =
 	Controller->V2.HealthStatusBuffer->StatusChangeCounter;
+      boolean ForceMonitoringCommand = false;
+      if (jiffies - Controller->SecondaryMonitoringTime
+	  > DAC960_SecondaryMonitoringInterval)
+	{
+	  int LogicalDriveNumber;
+	  for (LogicalDriveNumber = 0;
+	       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	       LogicalDriveNumber++)
+	    {
+	      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+		Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	      if (LogicalDeviceInfo == NULL) continue;
+	      if (!LogicalDeviceInfo->LogicalDeviceControl
+				     .LogicalDeviceInitialized &&
+		  Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 0)
+		{
+		  ForceMonitoringCommand = true;
+		  break;
+		}
+	    }
+	  Controller->SecondaryMonitoringTime = jiffies;
+	}
       if (StatusChangeCounter == Controller->V2.StatusChangeCounter &&
 	  Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
 	  == Controller->V2.NextEventSequenceNumber &&
@@ -4776,7 +4926,8 @@
 	   ControllerInfo->RebuildsActive +
 	   ControllerInfo->OnlineExpansionsActive == 0 ||
 	   jiffies - Controller->PrimaryMonitoringTime
-	   < DAC960_MonitoringTimerInterval))
+	   < DAC960_MonitoringTimerInterval) &&
+	  !ForceMonitoringCommand)
 	{
 	  Controller->MonitoringTimer.expires =
 	    jiffies + DAC960_HealthStatusMonitoringInterval;
@@ -4895,8 +5046,7 @@
   DiskGeometry_T Geometry, *UserGeometry;
   DAC960_Controller_T *Controller;
   int PartitionNumber;
-  if (File == NULL) return -EINVAL;
-  if (File->f_flags & O_NONBLOCK)
+  if (File != NULL && (File->f_flags & O_NONBLOCK))
     return DAC960_UserIOCTL(Inode, File, Request, Argument);
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
@@ -5136,10 +5286,17 @@
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
-						     [DCDB.TargetID] ||
-		   (Command = DAC960_AllocateCommand(Controller)) == NULL)
+	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
+	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
+						     [DCDB.TargetID])
+	      {
+		spin_unlock_irq(&io_request_lock);
+		__wait_event(Controller->CommandWaitQueue,
+			     !Controller->V1.DirectCommandActive
+					     [DCDB.Channel][DCDB.TargetID]);
+		spin_lock_irq(&io_request_lock);
+	      }
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = true;
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -5148,8 +5305,8 @@
 	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    Command->V1.CommandMailbox.Type3.BusAddress =
-	      Virtual_to_Bus(&DCDB);
-	    DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus32(&DCDB);
+	    DCDB.BusAddress = Virtual_to_Bus32(DataTransferBuffer);
 	  }
 	else
 	  {
@@ -5163,7 +5320,7 @@
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DataTransferBuffer);
+		Virtual_to_Bus32(DataTransferBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
 	CommandStatus = Command->V1.CommandStatus;
@@ -5276,7 +5433,7 @@
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	      Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus64(DataTransferBuffer);
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -5288,7 +5445,7 @@
 				  .NoAutoRequestSense = false;
 	    CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
 	    CommandMailbox->Common.RequestSenseBusAddress =
-	      Virtual_to_Bus(RequestSenseBuffer);
+	      Virtual_to_Bus64(RequestSenseBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
 	CommandStatus = Command->V2.CommandStatus;
@@ -5468,9 +5625,9 @@
 	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    Command->V1.CommandMailbox.Type3.BusAddress =
-	      Virtual_to_Bus(DCDB);
+	      Virtual_to_Bus32(DCDB);
 	    Command->V1.KernelCommand = KernelCommand;
-	    DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer);
+	    DCDB->BusAddress = Virtual_to_Bus32(DataTransferBuffer);
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	  }
@@ -5489,7 +5646,7 @@
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DataTransferBuffer);
+		Virtual_to_Bus32(DataTransferBuffer);
 	    Command->V1.KernelCommand = KernelCommand;
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -5566,7 +5723,7 @@
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	      Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus64(DataTransferBuffer);
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -5577,7 +5734,7 @@
 	    CommandMailbox->Common.CommandControlBits
 				  .NoAutoRequestSense = false;
 	    CommandMailbox->Common.RequestSenseBusAddress =
-	      Virtual_to_Bus(RequestSenseBuffer);
+	      Virtual_to_Bus64(RequestSenseBuffer);
 	  }
 	Command->V2.KernelCommand = KernelCommand;
 	DAC960_QueueCommand(Command);
@@ -5669,7 +5826,7 @@
 	    }
 	  if (MessageLevel == DAC960_AnnounceLevel)
 	    {
-	      static int AnnouncementLines;
+	      static int AnnouncementLines = 0;
 	      if (++AnnouncementLines <= 2)
 		printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel],
 		       Buffer);
@@ -6015,7 +6172,7 @@
       CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
       CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
       CommandMailbox->Type3R.BusAddress =
-	Virtual_to_Bus(&OldRebuildRateConstant);
+	Virtual_to_Bus32(&OldRebuildRateConstant);
       DAC960_ExecuteCommand(Command);
       switch (Command->V1.CommandStatus)
 	{
@@ -6071,7 +6228,7 @@
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentDataPointer =
-    Virtual_to_Bus(&PhysicalToLogicalDevice);
+    Virtual_to_Bus64(&PhysicalToLogicalDevice);
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentByteCount =
diff -urN linux-2.4.2-pre4/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- linux-2.4.2-pre4/drivers/block/DAC960.h	Mon Aug 21 09:23:54 2000
+++ linux/drivers/block/DAC960.h	Mon Dec  3 22:29:15 2001
@@ -2,7 +2,7 @@
 
   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -259,6 +259,7 @@
   DAC960_V1_ClearBadDataTable =			0x26,
   DAC960_V1_GetErrorTable =			0x17,
   DAC960_V1_AddCapacityAsync =			0x2A,
+  DAC960_V1_BackgroundInitializationControl =	0x2B,
   /* Configuration Related Commands */
   DAC960_V1_ReadConfig2 =			0x3D,
   DAC960_V1_WriteConfig2 =			0x3C,
@@ -450,14 +451,16 @@
   unsigned int NonVolatileMemorySize;			/* Bytes 36-39 */
   struct {
     enum {
-      DAC960_V1_DRAM =				0x0,
-      DAC960_V1_EDO =				0x1,
-      DAC960_V1_SDRAM =				0x2
+      DAC960_V1_RamType_DRAM =			0x0,
+      DAC960_V1_RamType_EDO =			0x1,
+      DAC960_V1_RamType_SDRAM =			0x2,
+      DAC960_V1_RamType_Last =			0x7
     } __attribute__ ((packed)) RamType:3;		/* Byte 40 Bits 0-2 */
     enum {
-      DAC960_V1_None =				0x0,
-      DAC960_V1_Parity =			0x1,
-      DAC960_V1_ECC =				0x2
+      DAC960_V1_ErrorCorrection_None =		0x0,
+      DAC960_V1_ErrorCorrection_Parity =	0x1,
+      DAC960_V1_ErrorCorrection_ECC =		0x2,
+      DAC960_V1_ErrorCorrection_Last =		0x7
     } __attribute__ ((packed)) ErrorCorrection:3;	/* Byte 40 Bits 3-5 */
     boolean FastPageMode:1;				/* Byte 40 Bit 6 */
     boolean LowPowerMemory:1;				/* Byte 40 Bit 7 */
@@ -523,7 +526,9 @@
   struct {
     boolean Clustering:1;				/* Byte 116 Bit 0 */
     boolean MylexOnlineRAIDExpansion:1;			/* Byte 116 Bit 1 */
-    unsigned int :30;					/* Bytes 116-119 */
+    boolean ReadAhead:1;				/* Byte 116 Bit 2 */
+    boolean BackgroundInitialization:1;			/* Byte 116 Bit 3 */
+    unsigned int :28;					/* Bytes 116-119 */
   } FirmwareFeatures;
   unsigned int :32;					/* Bytes 120-123 */
   unsigned int :32;					/* Bytes 124-127 */
@@ -993,7 +998,8 @@
     DAC960_V2_MemoryType_DRAM =			0x01,
     DAC960_V2_MemoryType_EDRAM =		0x02,
     DAC960_V2_MemoryType_EDO =			0x03,
-    DAC960_V2_MemoryType_SDRAM =		0x04
+    DAC960_V2_MemoryType_SDRAM =		0x04,
+    DAC960_V2_MemoryType_Last =			0x1F
   } __attribute__ ((packed)) MemoryType:5;		/* Byte 0 Bits 0-4 */
   boolean :1;						/* Byte 0 Bit 5 */
   boolean MemoryParity:1;				/* Byte 0 Bit 6 */
@@ -1269,13 +1275,15 @@
       DAC960_V2_ReadCacheDisabled =		0x0,
       DAC960_V2_ReadCacheEnabled =		0x1,
       DAC960_V2_ReadAheadEnabled =		0x2,
-      DAC960_V2_IntelligentReadAheadEnabled =	0x3
+      DAC960_V2_IntelligentReadAheadEnabled =	0x3,
+      DAC960_V2_ReadCache_Last =		0x7
     } __attribute__ ((packed)) ReadCache:3;		/* Byte 8 Bits 0-2 */
     enum {
       DAC960_V2_WriteCacheDisabled =		0x0,
       DAC960_V2_LogicalDeviceReadOnly =		0x1,
       DAC960_V2_WriteCacheEnabled =		0x2,
-      DAC960_V2_IntelligentWriteCacheEnabled =	0x3
+      DAC960_V2_IntelligentWriteCacheEnabled =	0x3,
+      DAC960_V2_WriteCache_Last =		0x7
     } __attribute__ ((packed)) WriteCache:3;		/* Byte 8 Bits 3-5 */
     boolean :1;						/* Byte 8 Bit 6 */
     boolean LogicalDeviceInitialized:1;			/* Byte 8 Bit 7 */
@@ -2336,6 +2344,7 @@
       boolean NeedDeviceSerialNumberInformation;
       boolean NeedRebuildProgress;
       boolean NeedConsistencyCheckProgress;
+      boolean StartDeviceStateScan;
       boolean RebuildProgressFirst;
       boolean RebuildFlagPending;
       boolean RebuildStatusPending;
@@ -2375,6 +2384,8 @@
       boolean NeedLogicalDeviceInformation;
       boolean NeedPhysicalDeviceInformation;
       boolean NeedDeviceSerialNumberInformation;
+      boolean StartLogicalDeviceInformationScan;
+      boolean StartPhysicalDeviceInformationScan;
       DAC960_V2_CommandMailbox_T *FirstCommandMailbox;
       DAC960_V2_CommandMailbox_T *LastCommandMailbox;
       DAC960_V2_CommandMailbox_T *NextCommandMailbox;
@@ -2397,6 +2408,7 @@
       DAC960_V2_PhysicalDevice_T
 	LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives];
       DAC960_V2_Event_T Event;
+      boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives];
     } V2;
   } FW;
   DiskPartition_T DiskPartitions[DAC960_MinorCount];
@@ -2503,26 +2515,39 @@
 
 
 /*
-  Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
+  Virtual_to_Bus32 maps from Kernel Virtual Addresses to 32 Bit PCI Bus
+  Addresses.
 */
 
-static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress)
+static inline DAC960_BusAddress32_T Virtual_to_Bus32(void *VirtualAddress)
 {
   return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress);
 }
 
 
 /*
-  Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
+  Bus32_to_Virtual maps from 32 Bit PCI Bus Addresses to Kernel Virtual
+  Addresses.
 */
 
-static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress)
+static inline void *Bus32_to_Virtual(DAC960_BusAddress32_T BusAddress)
 {
   return (void *) bus_to_virt(BusAddress);
 }
 
 
 /*
+  Virtual_to_Bus64 maps from Kernel Virtual Addresses to 64 Bit PCI Bus
+  Addresses.
+*/
+
+static inline DAC960_BusAddress64_T Virtual_to_Bus64(void *VirtualAddress)
+{
+  return (DAC960_BusAddress64_T) virt_to_bus(VirtualAddress);
+}
+
+
+/*
   Define the DAC960 BA Series Controller Interface Register Offsets.
 */
 
@@ -2789,8 +2814,13 @@
 void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress,
 				    DAC960_V2_CommandMailbox_T *CommandMailbox)
 {
-  writel(Virtual_to_Bus(CommandMailbox),
+#ifdef __ia64__
+  writeq(Virtual_to_Bus64(CommandMailbox),
 	 ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset);
+#else
+  writel(Virtual_to_Bus32(CommandMailbox),
+	 ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset);
+#endif
 }
 
 static inline DAC960_V2_CommandIdentifier_T
@@ -3090,8 +3120,13 @@
 void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress,
 				    DAC960_V2_CommandMailbox_T *CommandMailbox)
 {
-  writel(Virtual_to_Bus(CommandMailbox),
+#ifdef __ia64__
+  writeq(Virtual_to_Bus64(CommandMailbox),
+	 ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset);
+#else
+  writel(Virtual_to_Bus32(CommandMailbox),
 	 ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset);
+#endif
 }
 
 static inline DAC960_V2_CommandIdentifier_T
diff -urN linux-2.4.2-pre4/drivers/block/xd.c linux/drivers/block/xd.c
--- linux-2.4.2-pre4/drivers/block/xd.c	Thu Oct 26 23:35:47 2000
+++ linux/drivers/block/xd.c	Mon Dec  3 22:29:15 2001
@@ -28,6 +28,9 @@
  *   Recovered DMA access. Abridged messages. Added support for DTC5051CX,
  *   WD1002-27X & XEBEC controllers. Driver uses now some jumper settings.
  *   Extended ioctl() support.
+ *
+ * Bugfix: 15/02/01, Paul G. - inform queue layer of tiny xd_maxsect.
+ *
  */
 
 #include <linux/module.h>
@@ -59,7 +62,7 @@
 #define XD_INIT_DISK_DELAY	(30*HZ/1000)  /* 30 ms delay during disk initialization */
 
 /* Above may need to be increased if a problem with the 2nd drive detection
-   (ST11M controller) or resetting a controler (WD) appears */
+   (ST11M controller) or resetting a controller (WD) appears */
 
 XD_INFO xd_info[XD_MAXDRIVES];
 
@@ -118,6 +121,7 @@
 static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
 static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES];
 static int xd_blocksizes[XD_MAXDRIVES << 6];
+static int xd_maxsect[XD_MAXDRIVES << 6];
 
 extern struct block_device_operations xd_fops;
 
@@ -242,6 +246,10 @@
 			printk("xd: unable to get IRQ%d\n",xd_irq);
 	}
 
+	/* xd_maxsectors depends on controller - so set after detection */
+	for(i=0; i<(XD_MAXDRIVES << 6); i++) xd_maxsect[i] = xd_maxsectors;
+	max_sectors[MAJOR_NR] = xd_maxsect;
+
 	for (i = 0; i < xd_drives; i++) {
 		xd_valid[i] = 1;
 		register_disk(&xd_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, &xd_fops,
@@ -877,7 +885,7 @@
 				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
 					((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
 		}
-	/* 1002 based RLL controler requests converted addressing, but reports physical 
+	/* 1002 based RLL controller requests converted addressing, but reports physical 
 	   (physical 26 sec., logical 17 sec.) 
 	   1004 based ???? */
 		if (rll & wd_1002) {
@@ -1058,7 +1066,7 @@
 	xd_info[drive].control = 0;
 }
 
-/* xd_setup: initialise controler from command line parameters */
+/* xd_setup: initialise controller from command line parameters */
 void __init do_xd_setup (int *integers)
 {
 	switch (integers[0]) {
diff -urN linux-2.4.2-pre4/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- linux-2.4.2-pre4/drivers/cdrom/sbpcd.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/cdrom/sbpcd.c	Mon Dec  3 22:29:15 2001
@@ -323,7 +323,7 @@
  *		Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000
  *
  *  4.64 Fix module parameters - were being completely ignored.
- *	 Can also specify max_drives as 3rd setup int to get rid of
+ *	 Can also specify max_drives=N as a setup int to get rid of
  *	 "ghost" drives on crap hardware (aren't they all?)   Paul Gortmaker
  *
  *  TODO
@@ -339,6 +339,15 @@
  *
  */
 
+/*
+ * Trying to merge requests breaks this driver horribly (as in it goes
+ * boom and apparently has done so since 2.3.41).  As it is a legacy 
+ * driver for a horribly slow double speed CD on a hideous interface 
+ * designed for polled operation, I won't loose any sleep in simply 
+ * disallowing merging.				Paul G.  02/2001
+ */
+#define DONT_MERGE_REQUESTS
+
 #ifndef SBPCD_ISSUE
 #define SBPCD_ISSUE 1
 #endif SBPCD_ISSUE
@@ -476,7 +485,8 @@
 #else
 static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
 #endif
-MODULE_PARM(sbpcd, "3i");
+MODULE_PARM(sbpcd, "2i");
+MODULE_PARM(max_drives, "i");
 
 #define NUM_PROBE  (sizeof(sbpcd) / sizeof(int))
 
@@ -5566,7 +5576,6 @@
 #else
 	sbpcd_ioaddr = sbpcd[0];
 	sbpro_type = sbpcd[1];
-	max_drives = sbpcd[2];
 #endif
 	
 	CDo_command=sbpcd_ioaddr;
@@ -5661,6 +5670,21 @@
 	msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr);
 	return (0);
 }
+
+#ifdef DONT_MERGE_REQUESTS
+static int dont_merge_requests_fn(request_queue_t *q, struct request *req,
+                                struct request *next, int max_segments)
+{
+	return 0;
+}
+
+static int dont_bh_merge_fn(request_queue_t *q, struct request *req,
+                            struct buffer_head *bh, int max_segments)
+{
+	return 0;
+}
+#endif
+
 /*==========================================================================*/
 /*
  *  Test for presence of drive and initialize it.
@@ -5828,6 +5852,11 @@
 #endif MODULE
 	}
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+#ifdef DONT_MERGE_REQUESTS
+	(BLK_DEFAULT_QUEUE(MAJOR_NR))->back_merge_fn = dont_bh_merge_fn;
+	(BLK_DEFAULT_QUEUE(MAJOR_NR))->front_merge_fn = dont_bh_merge_fn;
+	(BLK_DEFAULT_QUEUE(MAJOR_NR))->merge_requests_fn = dont_merge_requests_fn;
+#endif
 	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
 	read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512);
 	
diff -urN linux-2.4.2-pre4/drivers/char/README.computone linux/drivers/char/README.computone
--- linux-2.4.2-pre4/drivers/char/README.computone	Mon Apr 24 13:39:34 2000
+++ linux/drivers/char/README.computone	Mon Dec  3 22:29:15 2001
@@ -92,7 +92,7 @@
 to update the character drivers' makefile and configuration file, and other 
 kernel source files. A build script (ip2build) was included which applies 
 the patches if needed, and build any utilities needed.
-What you recieve may be a single patch file in conventional kernel
+What you receive may be a single patch file in conventional kernel
 patch format build script. That form can also be applied by
 running patch -p1 < ThePatchFile.  Otherwise the drivers source may be
 a tar file, then untar and run ip2build if a new installation.
diff -urN linux-2.4.2-pre4/drivers/char/README.epca linux/drivers/char/README.epca
--- linux-2.4.2-pre4/drivers/char/README.epca	Wed Dec  6 12:06:18 2000
+++ linux/drivers/char/README.epca	Mon Dec  3 22:29:15 2001
@@ -319,7 +319,7 @@
 
                         1.  Removed code from pc_close which closes the 
                             drivers line discipline and restores its original
-                            line discipline.  This is currently unecessary,
+                            line discipline.  This is currently unnecessary,
                             though future fast cook enhancements may require
                             this.
 
diff -urN linux-2.4.2-pre4/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- linux-2.4.2-pre4/drivers/char/amiserial.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/amiserial.c	Mon Dec  3 22:29:15 2001
@@ -59,9 +59,6 @@
  * End of serial driver configuration section.
  */
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
 
 #include <linux/types.h>
diff -urN linux-2.4.2-pre4/drivers/char/cd1865.h linux/drivers/char/cd1865.h
--- linux-2.4.2-pre4/drivers/char/cd1865.h	Thu Mar  5 11:55:06 1998
+++ linux/drivers/char/cd1865.h	Mon Dec  3 22:29:15 2001
@@ -56,7 +56,7 @@
 #define CD186x_EOIR      0x7f    /* End of Interrupt Register               */
 #define CD186x_MRAR      0x75    /* Modem Request Acknowlege register       */
 #define CD186x_TRAR      0x76    /* Transmit Request Acknowlege register    */
-#define CD186x_RRAR      0x77    /* Recieve Request Acknowlege register     */
+#define CD186x_RRAR      0x77    /* Receive Request Acknowlege register     */
 #define CD186x_SRCR      0x66    /* Service Request Configuration register  */
 
 /* Channel Registers */
diff -urN linux-2.4.2-pre4/drivers/char/dtlk.c linux/drivers/char/dtlk.c
--- linux-2.4.2-pre4/drivers/char/dtlk.c	Sun Dec 31 10:26:18 2000
+++ linux/drivers/char/dtlk.c	Mon Dec  3 22:29:15 2001
@@ -47,10 +47,6 @@
 
  */
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
 #include <linux/module.h>
 #include <linux/version.h>
 
diff -urN linux-2.4.2-pre4/drivers/char/dz.c linux/drivers/char/dz.c
--- linux-2.4.2-pre4/drivers/char/dz.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/dz.c	Mon Dec  3 22:29:15 2001
@@ -230,7 +230,7 @@
 
     ch = UCHAR(status);                /* grab the char */
 
-#ifdef 0
+#if 0
     if (info->is_console) {
       if (ch == 0) return;            /* it's a break ... */
 
diff -urN linux-2.4.2-pre4/drivers/char/epca.c linux/drivers/char/epca.c
--- linux-2.4.2-pre4/drivers/char/epca.c	Sun Dec 31 10:26:17 2000
+++ linux/drivers/char/epca.c	Mon Dec  3 22:29:15 2001
@@ -2216,7 +2216,7 @@
 
 	/* -------------------------------------------------------------------
 		This routine is called upon every timer interrupt.  Even though
-		the Digi series cards are capable of generating interupts this 
+		the Digi series cards are capable of generating interrupts this 
 		method of non-looping polling is more efficient.  This routine
 		checks for card generated events (Such as receive data, are transmit
 		buffer empty) and acts on those events.
diff -urN linux-2.4.2-pre4/drivers/char/ftape/lowlevel/fdc-isr.c linux/drivers/char/ftape/lowlevel/fdc-isr.c
--- linux-2.4.2-pre4/drivers/char/ftape/lowlevel/fdc-isr.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/ftape/lowlevel/fdc-isr.c	Mon Dec  3 22:29:15 2001
@@ -237,7 +237,7 @@
 
 	switch (cause) {
 	case no_error: 
-		TRACE(ft_t_flow,"%d Sector(s) transfered", buff->sector_count);
+		TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count);
 		break;
 	case no_data_error:
 		TRACE(ft_t_flow, "Sector %d not found",
diff -urN linux-2.4.2-pre4/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c
--- linux-2.4.2-pre4/drivers/char/i810_rng.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/i810_rng.c	Mon Dec  3 22:29:15 2001
@@ -26,7 +26,7 @@
 	----------------------------------------------------------
 
 	This software may be used and distributed according to the terms
-        of the GNU Public License, incorporated herein by reference.
+        of the GNU General Public License, incorporated herein by reference.
 
 	----------------------------------------------------------
 
diff -urN linux-2.4.2-pre4/drivers/char/ip2/i2hw.h linux/drivers/char/ip2/i2hw.h
--- linux-2.4.2-pre4/drivers/char/ip2/i2hw.h	Mon Aug 23 10:23:23 1999
+++ linux/drivers/char/ip2/i2hw.h	Mon Dec  3 22:29:15 2001
@@ -143,7 +143,7 @@
 //
 #define FIFO_DATA 0
 
-// Another way of passing information between the the board and the host is
+// Another way of passing information between the board and the host is
 // through "mailboxes". Unlike a FIFO, a mailbox holds only a single byte of
 // data.  Writing data to the mailbox causes a status bit to be set, and
 // potentially interrupting the intended receiver. The sender has some way to
diff -urN linux-2.4.2-pre4/drivers/char/ip2/i2lib.h linux/drivers/char/ip2/i2lib.h
--- linux-2.4.2-pre4/drivers/char/ip2/i2lib.h	Wed Jul  5 11:00:22 2000
+++ linux/drivers/char/ip2/i2lib.h	Mon Dec  3 22:29:15 2001
@@ -150,7 +150,7 @@
 	// though these are in the channel structure, the channel is also written
 	// here, the easier to send it to the fifo when ready. HOWEVER, individual
 	// packets here are NOT padded to even length: the routines for writing
-	// blocks to the the fifo will pad to even byte counts.
+	// blocks to the fifo will pad to even byte counts.
 	//
 	UCHAR	Obuf[OBUF_SIZE+MAX_OBUF_BLOCK+4];
 	volatile
diff -urN linux-2.4.2-pre4/drivers/char/ip2.c linux/drivers/char/ip2.c
--- linux-2.4.2-pre4/drivers/char/ip2.c	Tue Apr 25 17:52:01 2000
+++ linux/drivers/char/ip2.c	Mon Dec  3 22:29:15 2001
@@ -29,12 +29,6 @@
 ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 
 #ifdef MODULE
-#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
-#	define MODVERSIONS
-#endif
-#ifdef MODVERSIONS
-#	include <linux/modversions.h>
-#endif
 
 static int io[IP2_MAX_BOARDS]= { 0,};
 static int irq[IP2_MAX_BOARDS] = { 0,}; 
diff -urN linux-2.4.2-pre4/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- linux-2.4.2-pre4/drivers/char/ip2main.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/ip2main.c	Mon Dec  3 22:29:15 2001
@@ -50,14 +50,6 @@
 /************/
 #include <linux/config.h>
 // Uncomment the following if you want it compiled with modversions
-#ifdef MODULE
-#	if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
-#		define MODVERSIONS
-#	endif
-#	ifdef MODVERSIONS
-#		include <linux/modversions.h>
-#	endif
-#endif
 
 #include <linux/version.h>
 
diff -urN linux-2.4.2-pre4/drivers/char/joystick/amijoy.c linux/drivers/char/joystick/amijoy.c
--- linux-2.4.2-pre4/drivers/char/joystick/amijoy.c	Mon Aug 14 13:55:01 2000
+++ linux/drivers/char/joystick/amijoy.c	Mon Dec  3 22:29:15 2001
@@ -113,7 +113,7 @@
 	for (i = 0; i < 2; i++)
 		if (amijoy[i]) {
 			if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
-						amijoy [Denise]")) {
+						"amijoy [Denise]")) {
 				if (i == 1 && amijoy[0]) {
 					input_unregister_device(amijoy_dev);
 					release_mem_region(CUSTOM_PHYSADDR+10, 2);
diff -urN linux-2.4.2-pre4/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c
--- linux-2.4.2-pre4/drivers/char/pcmcia/serial_cb.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/pcmcia/serial_cb.c	Mon Dec  3 22:29:15 2001
@@ -7,7 +7,7 @@
     Copyright 1998, 1999 by Donald Becker and David Hinds
     
     This software may be used and distributed according to the terms
-    of the GNU Public License, incorporated herein by reference.
+    of the GNU General Public License, incorporated herein by reference.
     All other rights reserved.
     
     This driver is an activator for CardBus serial cards, as
diff -urN linux-2.4.2-pre4/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.2-pre4/drivers/char/pcmcia/serial_cs.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/pcmcia/serial_cs.c	Mon Dec  3 22:29:15 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- linux-2.4.2-pre4/drivers/char/pcxx.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/pcxx.c	Mon Dec  3 22:29:15 2001
@@ -5,7 +5,7 @@
  *
  *  Copyright (C) 1994,1995 Troy De Jongh
  *  This software may be used and distributed according to the terms 
- *  of the GNU Public License.
+ *  of the GNU General Public License.
  *
  *  This driver is for the DigiBoard PC/Xe and PC/Xi line of products.
  *
diff -urN linux-2.4.2-pre4/drivers/char/random.c linux/drivers/char/random.c
--- linux-2.4.2-pre4/drivers/char/random.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/random.c	Mon Dec  3 22:29:15 2001
@@ -20,7 +20,7 @@
  *    written permission.
  * 
  * ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
  * required INSTEAD OF the above restrictions.  (This clause is
  * necessary due to a potential bad interaction between the GPL and
  * the restrictions contained in a BSD-style copyright.)
diff -urN linux-2.4.2-pre4/drivers/char/rio/rio.h linux/drivers/char/rio/rio.h
--- linux-2.4.2-pre4/drivers/char/rio/rio.h	Wed May 10 16:56:44 2000
+++ linux/drivers/char/rio/rio.h	Mon Dec  3 22:29:15 2001
@@ -224,7 +224,7 @@
 
 #define	RIO_IPL	5
 #define	RIO_PRI	(PZERO+10)
-#define RIO_CLOSE_PRI	PZERO-1	/* uninteruptible sleeps for close */
+#define RIO_CLOSE_PRI	PZERO-1	/* uninterruptible sleeps for close */
 
 typedef struct DbInf
 {
diff -urN linux-2.4.2-pre4/drivers/char/rio/rioinfo.h linux/drivers/char/rio/rioinfo.h
--- linux-2.4.2-pre4/drivers/char/rio/rioinfo.h	Wed May 10 16:56:44 2000
+++ linux/drivers/char/rio/rioinfo.h	Mon Dec  3 22:29:15 2001
@@ -44,7 +44,7 @@
 	long	location;	/* RIO Card Base I/O address */
 	long	vector;		/* RIO Card IRQ vector */
 	int	bus;		/* ISA/EISA/MCA/PCI */
-	int	mode;		/* pointer to host mode - INTERUPT / POLLED */
+	int	mode;		/* pointer to host mode - INTERRUPT / POLLED */
 	struct old_sgttyb
 		* Sg;		/* pointer to default term characteristics */
 };
diff -urN linux-2.4.2-pre4/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c
--- linux-2.4.2-pre4/drivers/char/rio/riotable.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/rio/riotable.c	Mon Dec  3 22:29:15 2001
@@ -696,7 +696,7 @@
 
 	    /*
 	    ** Now we have a host we need to allocate an ID
-	    ** if the the entry does not already have one.
+	    ** if the entry does not already have one.
 	    */
 	    if (MapP->ID == (ushort)-1)
 	    {
diff -urN linux-2.4.2-pre4/drivers/char/rocket.c linux/drivers/char/rocket.c
--- linux-2.4.2-pre4/drivers/char/rocket.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/rocket.c	Mon Dec  3 22:29:15 2001
@@ -51,7 +51,7 @@
 #define MODULE
 #endif
 
-#ifdef NEW_MODULES
+#if defined(NEW_MODULES) && defined(LOCAL_ROCKET_H)
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
diff -urN linux-2.4.2-pre4/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.2-pre4/drivers/char/serial.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/char/serial.c	Mon Dec  3 22:29:15 2001
@@ -28,7 +28,7 @@
  *        Stanislav V. Voronyi <stas@uanet.kharkov.ua>
  *
  *  3/98: Change the IRQ detection, use of probe_irq_o*(),
- *	  supress TIOCSERGWILD and TIOCSERSWILD
+ *	  suppress TIOCSERGWILD and TIOCSERSWILD
  *	  Etienne Lorrain <etienne.lorrain@ibm.net>
  *
  *  4/98: Added changes to support the ARM architecture proposed by
@@ -165,9 +165,6 @@
  * End of serial driver configuration section.
  */
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
 
 #include <linux/types.h>
diff -urN linux-2.4.2-pre4/drivers/char/wd501p.h linux/drivers/char/wd501p.h
--- linux-2.4.2-pre4/drivers/char/wd501p.h	Mon Dec 11 12:59:17 2000
+++ linux/drivers/char/wd501p.h	Mon Dec  3 22:29:15 2001
@@ -11,7 +11,7 @@
  *
  *	http://www.cymru.net
  *
- *	This driver is provided under the GNU public license, incorporated
+ *	This driver is provided under the GNU General Public License, incorporated
  *	herein by reference. The driver is provided without warranty or 
  *	support.
  *
diff -urN linux-2.4.2-pre4/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c
--- linux-2.4.2-pre4/drivers/ide/cmd640.c	Thu Apr 13 22:54:26 2000
+++ linux/drivers/ide/cmd640.c	Mon Dec  3 22:29:15 2001
@@ -67,7 +67,7 @@
  *
  *  Version 0.09	Try to be smarter about 2nd port enabling.
  *  Version 0.10	Be nice and don't reset 2nd port.
- *  Version 0.11	Try to handle more wierd situations.
+ *  Version 0.11	Try to handle more weird situations.
  *
  *  Version 0.12	Lots of bug fixes from Laszlo Peter
  *			irq unmasking disabled for reliability.
diff -urN linux-2.4.2-pre4/drivers/ide/hd.c linux/drivers/ide/hd.c
--- linux-2.4.2-pre4/drivers/ide/hd.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/ide/hd.c	Mon Dec  3 22:29:15 2001
@@ -22,6 +22,9 @@
  *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
  *
  *  Modified 1995 Russell King for ARM processor.
+ *
+ *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ *  off in a hurry once you queue things up - Paul G. 02/2001
  */
   
 /* Uncomment the following if you want verbose error reports. */
@@ -104,6 +107,7 @@
 static int hd_sizes[MAX_HD<<6];
 static int hd_blocksizes[MAX_HD<<6];
 static int hd_hardsectsizes[MAX_HD<<6];
+static int hd_maxsect[MAX_HD<<6];
 
 static struct timer_list device_timer;
 
@@ -730,9 +734,11 @@
 	for(drive=0; drive < (MAX_HD << 6); drive++) {
 		hd_blocksizes[drive] = 1024;
 		hd_hardsectsizes[drive] = 512;
+		hd_maxsect[drive]=255;
 	}
 	blksize_size[MAJOR_NR] = hd_blocksizes;
 	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+	max_sectors[MAJOR_NR] = hd_maxsect;
 
 #ifdef __i386__
 	if (!NR_HD) {
diff -urN linux-2.4.2-pre4/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- linux-2.4.2-pre4/drivers/ide/pdc202xx.c	Fri Jul 28 12:08:30 2000
+++ linux/drivers/ide/pdc202xx.c	Mon Dec  3 22:29:16 2001
@@ -747,14 +747,11 @@
 {
 	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
 	byte udma_speed_flag	= inb(high_16 + 0x001f);
-	int i			= 0;
 
 	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	ide_delay_50ms();
-	ide_delay_50ms();
+	mdelay(100);
 	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	for (i = 0; i < 40; i++)
-		ide_delay_50ms();
+	mdelay(2000);		/* 2 seconds ?! */
 }
 
 unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
@@ -767,7 +764,6 @@
 	if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
 	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
 	    (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		int i = 0;
 		/*
 		 * software reset -  this is required because the bios
 		 * will set UDMA timing on if the hdd supports it. The
@@ -779,11 +775,9 @@
 		 */
 
 		OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-		ide_delay_50ms();
-		ide_delay_50ms();
+		mdelay(100);
 		OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-		for (i=0; i<40; i++)
-			ide_delay_50ms();
+		mdelay(2000);	/* 2 seconds ?! */
 	}
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
diff -urN linux-2.4.2-pre4/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- linux-2.4.2-pre4/drivers/isdn/avmb1/capi.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/isdn/avmb1/capi.c	Mon Dec  3 22:29:16 2001
@@ -252,7 +252,6 @@
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
 #include "capifs.h"
 #endif
-#include <linux/slab.h>
 
 static char *revision = "$Revision: 1.44.6.3 $";
 
diff -urN linux-2.4.2-pre4/drivers/media/video/Config.in linux/drivers/media/video/Config.in
--- linux-2.4.2-pre4/drivers/media/video/Config.in	Wed Aug 23 14:59:55 2000
+++ linux/drivers/media/video/Config.in	Mon Dec  3 22:29:16 2001
@@ -23,7 +23,7 @@
 fi
 dep_tristate '  CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
-  if [ "CONFIG_PARPORT_1284" != "n" ]; then
+  if [ "$CONFIG_PARPORT_1284" != "n" ]; then
     dep_tristate '    CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
   fi
   if [ "$CONFIG_USB" != "n" ]; then
diff -urN linux-2.4.2-pre4/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- linux-2.4.2-pre4/drivers/media/video/bttv-cards.c	Sat Dec 30 11:23:13 2000
+++ linux/drivers/media/video/bttv-cards.c	Mon Dec  3 22:29:16 2001
@@ -6,7 +6,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -53,6 +53,7 @@
 
 /* config variables */
 static int triton1=0;
+int no_overlay=-1;
 static unsigned int card[4]  = { -1, -1, -1, -1 };
 static unsigned int pll[4]   = { -1, -1, -1, -1 };
 static unsigned int tuner[4] = { -1, -1, -1, -1 };
@@ -67,6 +68,7 @@
 
 /* insmod options */
 MODULE_PARM(triton1,"i");
+MODULE_PARM(no_overlay,"i");
 MODULE_PARM(card,"1-4i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
 MODULE_PARM(pll,"1-4i");
@@ -115,10 +117,11 @@
 	{ 0x00031002, BTTV_HAUPPAUGE878,  "ATI TV Wonder/VE" },
 	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
 	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
 	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV/Radio+" },
-	{ 0x1200bd11, BTTV_PINNACLERAVE,  "Pinnacle PCTV Rave" },
+	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
 	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
 	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
@@ -131,6 +134,7 @@
 	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
 	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
  	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
 	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
@@ -219,12 +223,16 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		3,
+	/* old 
 	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{12, 4,11,11, 0},
+	*/
+	muxsel:		{ 2, 3, 1, 1},
+	gpiomask:	0x0f,
+	audiomux:	{ 0x04, 0x04, 0x08, 0x04, 0},
 	needs_tvaudio:	1,
-	pll:		PLL_28,
 	tuner_type:	-1,
+	audio_hook:	avermedia_tvphone_audio,
 },{
 	name:		"MATRIX-Vision MV-Delta",
 	video_inputs:	5,
@@ -278,9 +286,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	65551,
+	gpiomask:	0x3000f,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{1,65537, 0, 0,10},
+	audiomux:	{ 1,0x10001, 0, 0,10},
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
@@ -421,8 +429,8 @@
 	muxsel:		{ 2, 3 },
 	audiomux:	{ 0, 0, 0, 0, 0 },
 	no_msp34xx:	1,
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	pll:            PLL_28,
+	tuner_type:     TUNER_ALPS_TSBB5_PAL_I,
 },{
 
 /* ---- card 0x18 ---------------------------------- */
@@ -480,16 +488,17 @@
 	svhs:		2,
 	gpiomask:	0x70000,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},
+	audiomux:	{ 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 	audio_hook:	terratv_audio,
 },{
+	/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
 	name:		"Imagenation PXC200",
 	video_inputs:	5,
 	audio_inputs:	1,
 	tuner:		-1,
-	svhs:		4,
+	svhs:		1, /* was: 4 */
 	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 0, 0},
 	audiomux:	{ 0 },
@@ -539,7 +548,8 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x500, 0, 0x300, 0x900, 0x900},
 	needs_tvaudio:	1,
-	tuner_type:	-1,
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
 },{
 	name:		"Leadtek WinFast 2000",
 	video_inputs:	3,
@@ -603,7 +613,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"Pinnacle PCTV Rave",
+	name:		"Pinnacle PCTV Studio/Rave",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -636,11 +646,10 @@
 	svhs:		2,
 	gpiomask:	12,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 13, 14, 11, 7, 0, 0},
+	audiomux:	{ 13, 4, 11, 7, 0, 0},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	5,
-	audio_hook:	avermedia_tvphone_audio,
 },{
 	name:		"ProVideo PV951", /* pic16c54 */
 	video_inputs:	3,
@@ -691,17 +700,17 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"Zoltrix Genie TV",
+	name:		"Zoltrix Genie TV/FM",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0xbcf03f,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f},
+	audiomux:	{ 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
 	no_msp34xx:	1,
 	pll:		PLL_28,
-	tuner_type:	5,
+	tuner_type:	21,
 },{
 	name:		"Terratec TV/Radio+",
 	video_inputs:	3,
@@ -767,29 +776,105 @@
 },{
 
 /* ---- card 0x34 ---------------------------------- */
-	name:           "Pinnacle Studio PCTV Pro", /* David Härdeman <david@2gen.com> */
+	/* David Härdeman <david@2gen.com> */
+	name:           "Pinnacle PCTV Studio Pro",
 	video_inputs:   3,
 	audio_inputs:   1,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x03000F,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1, 65537, 0, 0, 10},
+	audiomux:	{ 1, 0x10001, 0, 0, 10},
 	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     -1,
 },{
-	name:		"Typhoon TView RDS", /* Claas Langbehn <claas@bigfoot.com> */
+	/* Claas Langbehn <claas@bigfoot.com>,
+	   Sven Grothklags <sven@upb.de> */
+	name:		"Typhoon TView RDS / FM Stereo",
 	video_inputs:	3,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xffff,
+	gpiomask:	0x1c,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xb002, 0, 0x12, 0x12, 0x3007 },
+	audiomux:	{ 0, 0, 0x10, 8, 4 },
 	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL_I,
+},{
+	/* Tim Röstermundt <rosterm@uni-muenster.de>
+	   in de.comp.os.unix.linux.hardware:
+		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+		options tuner type=5 */
+	name:		"Livetec 9415 TV",
+	video_inputs:	4,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0x18e0,
+	muxsel:		{ 2, 3, 1, 1},
+	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
+},{
+	/* Miguel Angel Alvarez <maacruz@navegalia.com> */
+	name:           "BESTBUY Easy TV",
+	video_inputs:	4,
+	audio_inputs:   1,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:       0xF,
+	muxsel:         { 2, 3, 1, 0},
+	audiomux:       { 2, 0, 0, 0, 10},
+	needs_tvaudio:  0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_PAL_I,
+},{
+
+/* ---- card 0x38 ---------------------------------- */
+	/* Gordon Heydon <gjheydon@bigfoot.com */
+	name:           "FlyVideo '98/FM",
+	video_inputs:   3,
+	audio_inputs:   3,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:       0x1800,
+	muxsel:         { 2, 3, 1, 1},
+	audiomux:       { 0, 0x800, 0, 0, 0x1800, 0 },
+	needs_tvaudio:  1,
+	pll:            PLL_28,
+	tuner_type:     -1,
+},{
+	/* This is the ultimate cheapo capture card 
+	 * just a BT848A on a small PCB!
+	 * Steve Hosgood <steve@equiinet.com> */
+	name:           "GrandTec 'Grand Video Capture'",
+	video_inputs:   2,
+	audio_inputs:   0,
+	tuner:          -1,
+	svhs:           1,
+	gpiomask:       0,
+	muxsel:         { 3, 1 },
+	audiomux:       { 0 },
+	needs_tvaudio:  0,
+	no_msp34xx:     1,
+	pll:            PLL_35,
+	tuner_type:     -1,
+},{
+        /* Daniel Herrington <daniel.herrington@home.com> */
+        name:           "Phoebe TV Master Only (No FM)",
+        video_inputs:   3,
+        audio_inputs:   1,
+        tuner:          0,
+        svhs:           2,
+        gpiomask:       0x0e00,
+        muxsel:         { 2, 3, 1, 1},
+        audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+        needs_tvaudio:  1,
+        pll:            PLL_NONE,
+        tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -876,32 +961,76 @@
 /*
  * (most) board specific initialisations goes here
  */
+
+int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
+			14,2,17,1, 4,1,4,3,  1,2,16,1, 4,4,4,4 };
+int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
+			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,0,0,0 };
+
 void __devinit bttv_init_card(struct bttv *btv)
 {
-	int eeprom = 0;
-
-        if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
-                /* auto detect tuner for MIRO cards */
-                btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+	/* miro/pinnacle */
+        if (btv->type == BTTV_MIRO      ||
+	    btv->type == BTTV_MIROPRO   ||
+	    btv->type == BTTV_PINNACLE  ||
+	    btv->type == BTTV_PINNACLEPRO) {
+		int id,msp;
+		id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
+		msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
+		btv->tuner_type = miro_tunermap[id];
+		if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
+			btv->has_radio = 1;
+			if (!miro_fmtuner[id]) {
+				btv->has_matchbox = 1;
+				btv->mbox_we    = (1<<6);
+				btv->mbox_most  = (1<<7);
+				btv->mbox_clk   = (1<<8);
+				btv->mbox_data  = (1<<9);
+				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+			}
+		} else {
+			btv->has_radio = 0;
+		}
+		if (-1 != msp) {
+			if (btv->type == BTTV_MIRO)
+				btv->type = BTTV_MIROPRO;
+			if (btv->type == BTTV_PINNACLE)
+				btv->type = BTTV_PINNACLEPRO;
+		}
+		if (bttv_verbose)
+			printk("bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+			       btv->nr, id+1, btv->tuner_type,
+			       !btv->has_radio ? "no" :
+				   (btv->has_matchbox ? "matchbox" : "fmtuner"),
+			       (-1 == msp) ? "no" : "yes");
 #if 0
-		if (btv->type == BTTV_MIROPRO) {
+		if (btv->has_matchbox) {
 			if (bttv_verbose)
 				printk(KERN_INFO "Initializing TEA5757...\n");
 			init_tea5757(btv);
 		}
 #endif
-        }
+	}
+
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
 		/* pick up some config infos from the eeprom */
-		if (0xa0 != eeprom) {
-			eeprom = 0xa0;
-			bttv_readee(btv,eeprom_data,0xa0);
-		}
+		bttv_readee(btv,eeprom_data,0xa0);
                 hauppauge_eeprom(btv);
         }
+
  	if (btv->type == BTTV_PXC200)
 		init_PXC200(btv);
 
+	if (btv->type == BTTV_VHX) {
+		btv->has_radio    = 1;
+		btv->has_matchbox = 1;
+		btv->mbox_we      = 0x20;
+		btv->mbox_most    = 0;
+		btv->mbox_clk     = 0x08;
+		btv->mbox_data    = 0x10;
+		btv->mbox_mask    = 0x38;
+	}
+
 	/* pll configuration */
         if (!(btv->id==848 && btv->revision==0x11)) {
 		/* defaults from card list */
@@ -985,59 +1114,80 @@
         { TUNER_ABSENT,        "" },
         { TUNER_ABSENT,        "External" },
         { TUNER_ABSENT,        "Unspecified" },
-        { TUNER_ABSENT,        "Philips FI1216" },
+        { TUNER_PHILIPS_PAL,   "Philips FI1216" },
         { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
         { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
-        { TUNER_ABSENT,        "Philips FI1246" },
-        { TUNER_ABSENT,        "Philips FI1256" },
+        { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
+        { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
         { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
         { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
         { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
         { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
-        { TUNER_ABSENT,        "Philips FI1256 MK2" },
-        { TUNER_ABSENT,        "Temic 4032FY5" },
+        { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
+        { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
         { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
         { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
-        { TUNER_ABSENT,        "Philips FR1216 MK2" },
+        { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
         { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
         { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
         { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
-        { TUNER_ABSENT,        "Philips FR1256 MK2" },
+        { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
         { TUNER_PHILIPS_PAL,   "Philips FM1216" },
-        { TUNER_ABSENT,        "Philips FM1216MF" },
+        { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
         { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
         { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
-        { TUNER_ABSENT,        "Philips FM1256" },
-        { TUNER_TEMIC_4036FY5_NTSC,  "Temic 4036FY5" },
+        { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
+        { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
         { TUNER_ABSENT,        "Samsung TCPN9082D" },
         { TUNER_ABSENT,        "Samsung TCPM9092P" },
-        { TUNER_TEMIC_PAL,     "Temic 4006FH5" },
+        { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
         { TUNER_ABSENT,        "Samsung TCPN9085D" },
         { TUNER_ABSENT,        "Samsung TCPB9085P" },
         { TUNER_ABSENT,        "Samsung TCPL9091P" },
-        { TUNER_ABSENT,        "Temic 4039FR5" },
-        { TUNER_ABSENT,        "Philips FQ1216 ME" },
-        { TUNER_TEMIC_PAL_I,   "Temic 4066FY5" },
+        { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
+        { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
+        { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
         { TUNER_ABSENT,        "Philips TD1536" },
         { TUNER_ABSENT,        "Philips TD1536D" },
         { TUNER_ABSENT,        "Philips FMR1236" },
         { TUNER_ABSENT,        "Philips FI1256MP" },
         { TUNER_ABSENT,        "Samsung TCPQ9091P" },
-        { TUNER_ABSENT,        "Temic 4006FN5" },
-        { TUNER_ABSENT,        "Temic 4009FR5" },
-        { TUNER_ABSENT,        "Temic 4046FM5" },
+        { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
+        { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
+        { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
+	{ TUNER_ABSENT,        "Temic 4009FN5" },
+	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
+	{ TUNER_ABSENT,	       "LG TP18NSR01F"},
+	{ TUNER_ABSENT,        "LG TP18PSB01D"},
+	{ TUNER_ABSENT,        "LG TP18PSB11D"},	
+	{ TUNER_ABSENT,        "LG TAPC_l001D"},
+	{ TUNER_ABSENT,        "LG TAPC_l701D"}
 };
 
 static void __devinit hauppauge_eeprom(struct bttv *btv)
 {
-        if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) 
-        {
-                btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
-		if (bttv_verbose)
-			printk("bttv%d: Hauppauge eeprom: model=%d, tuner=%s (%d)\n",btv->nr,
-			       eeprom_data[12] << 8 | eeprom_data[11],
-			       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
-        }
+	int blk2,tuner,radio,model;
+
+	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0)
+		printk("bttv%d: Hauppauge eeprom: invalid\n",btv->nr);
+
+	/* Block 2 starts after len+3 bytes header */
+	blk2 = eeprom_data[1] + 3;
+
+	/* decode + use some config infos */
+	model = eeprom_data[12] << 8 | eeprom_data[11];
+	tuner = eeprom_data[9];
+	radio = eeprom_data[blk2-1] & 0x01;
+	
+        if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))
+                btv->tuner_type = hauppauge_tuner[tuner].id;
+	if (radio)
+		btv->has_radio = 1;
+	
+	if (bttv_verbose)
+		printk("bttv%d: Hauppauge eeprom: model=%d, tuner=%s (%d), radio=%s\n",
+		       btv->nr, model, hauppauge_tuner[tuner].name,
+		       btv->tuner_type, radio ? "yes" : "no");
 }
 
 void __devinit bttv_hauppauge_boot_msp34xx(struct bttv *btv)
@@ -1117,15 +1267,17 @@
  * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
  */
 
+#if 0
 /* bus bits on the GPIO port */
 #define TEA_WE			6
 #define TEA_DATA		9
 #define TEA_CLK			8
 #define TEA_MOST		7
+#endif
 
-#define BUS_LOW(bit) 	btand(~(1<<TEA_##bit), BT848_GPIO_DATA)
-#define BUS_HIGH(bit)	btor((1<<TEA_##bit), BT848_GPIO_DATA)
-#define BUS_IN(bit)	((btread(BT848_GPIO_DATA) >> TEA_##bit) & 1)
+#define BUS_LOW(bit) 	btand(~(bit), BT848_GPIO_DATA)
+#define BUS_HIGH(bit)	btor((bit), BT848_GPIO_DATA)
+#define BUS_IN(bit)	(btread(BT848_GPIO_DATA) & (bit))
 
 /* TEA5757 register bits */
 #define TEA_FREQ		0:14
@@ -1155,93 +1307,83 @@
 #define TEA_STATUS_SEARCHING	1
 
 /* Low-level stuff */
-static int tea_read(struct bttv *btv)
+static int tea5757_read(struct bttv *btv)
 {
 	int value = 0;
 	long timeout;
 	int i;
 	
 	/* better safe than sorry */
-	btaor((1<<TEA_CLK) | (1<<TEA_WE), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
+	btaor((btv->mbox_clk | btv->mbox_we),
+	      ~btv->mbox_mask, BT848_GPIO_OUT_EN);
 	if (bttv_gpio)
-		bttv_gpio_tracking(btv,"miro tea read");
+		bttv_gpio_tracking(btv,"tea5757 read");
 	
-	BUS_LOW(WE);
-	BUS_LOW(CLK);
+	BUS_LOW(btv->mbox_we);
+	BUS_LOW(btv->mbox_clk);
 	
 	udelay(10);
 	for(timeout = jiffies + 10 * HZ;
-	    BUS_IN(DATA) == 1 && time_before(jiffies, timeout);
+	    BUS_IN(btv->mbox_data) && time_before(jiffies, timeout);
 	    schedule());	/* 10 s */
-	if (BUS_IN(DATA) == 1) {
-		printk("tea5757: read timeout\n");
+	if (BUS_IN(btv->mbox_data)) {
+		printk("bttv%d: tea5757: read timeout\n",btv->nr);
 		return -1;
 	}
 	for(timeout = jiffies + HZ/5;
-	    BUS_IN(MOST) == 1 && time_before(jiffies, timeout);
+	    BUS_IN(btv->mbox_data) == 1 && time_before(jiffies, timeout);
 	    schedule());	/* 0.2 s */
-	if (bttv_debug) printk("tea5757:");
+	dprintk("bttv%d: tea5757:",btv->nr);
 	for(i = 0; i < 24; i++)
 	{
-		udelay(10);
-		BUS_HIGH(CLK);
-		udelay(10);
-		if (bttv_debug) printk("%c", (BUS_IN(MOST) == 0)?'T':'-');
-		BUS_LOW(CLK);
-		value <<= 1;					
-		value |= (BUS_IN(DATA) == 0)?0:1;	/* MSB first */
-		if (bttv_debug) printk("%c", (BUS_IN(MOST) == 0)?'S':'M');
+		udelay(5);
+		BUS_HIGH(btv->mbox_clk);
+		udelay(5);
+		dprintk("%c",(BUS_IN(btv->mbox_most) == 0)?'T':'-');
+		BUS_LOW(btv->mbox_clk);
+		value <<= 1;
+		value |= (BUS_IN(btv->mbox_data) == 0)?0:1;  /* MSB first */
+		dprintk("%c", (BUS_IN(btv->mbox_most) == 0)?'S':'M');
 	}
-	if (bttv_debug) printk("\ntea5757: read 0x%X\n", value);
+	dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value);
 	return value;
 }
 
-static int tea_write(struct bttv *btv, int value)
+static int tea5757_write(struct bttv *btv, int value)
 {
 	int i;
 	int reg = value;
 	
-	btaor((1<<TEA_CLK) | (1<<TEA_WE) | (1<<TEA_DATA), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
+	btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data,
+	      ~btv->mbox_mask, BT848_GPIO_OUT_EN);
 	if (bttv_gpio)
-		bttv_gpio_tracking(btv,"miro tea write");
-	if (bttv_debug)
-		printk("tea5757: write 0x%X\n", value);
-	BUS_LOW(CLK);
-	BUS_HIGH(WE);
+		bttv_gpio_tracking(btv,"tea5757 write");
+	dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value);
+	BUS_LOW(btv->mbox_clk);
+	BUS_HIGH(btv->mbox_we);
 	for(i = 0; i < 25; i++)
 	{
 		if (reg & 0x1000000)
-			BUS_HIGH(DATA);
+			BUS_HIGH(btv->mbox_data);
 		else
-			BUS_LOW(DATA);
+			BUS_LOW(btv->mbox_data);
 		reg <<= 1;
-		BUS_HIGH(CLK);
+		BUS_HIGH(btv->mbox_clk);
 		udelay(10);
-		BUS_LOW(CLK);
+		BUS_LOW(btv->mbox_clk);
 		udelay(10);
 	}
-	BUS_LOW(WE);	/* unmute !!! */
+	BUS_LOW(btv->mbox_we);  /* unmute !!! */
 	return 0;
 }
 
 void tea5757_set_freq(struct bttv *btv, unsigned short freq)
 {
-	tea_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-	if (bttv_debug) tea_read(btv);
+	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
+	if (bttv_debug)
+		tea5757_read(btv);
 }
 
-#if 0
-void init_tea5757(struct bttv *btv)
-{
-	BUS_LOW(CLK);
-	BUS_LOW(WE); /* just to be on the safe side... */
-
-	/* software CLK (unused) */
-	btaor(0, BT848_GPIO_DMA_CTL_GPCLKMODE, BT848_GPIO_DMA_CTL);
-	/* normal mode for GPIO */
-	btaor(0, BT848_GPIO_DMA_CTL_GPIOMODE, BT848_GPIO_DMA_CTL);
-}
-#endif
 
 /* ----------------------------------------------------------------------- */
 /* winview                                                                 */
@@ -1297,7 +1439,7 @@
 	unsigned int con = 0;
 
 	if (set) {
-		btor(0x100, BT848_GPIO_OUT_EN);
+		btor(0x300, BT848_GPIO_OUT_EN);
 		if (v->mode & VIDEO_SOUND_LANG1)
 			con = 0x000;
 		if (v->mode & VIDEO_SOUND_LANG2)
@@ -1322,21 +1464,22 @@
  *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
  *  input/output sound connection, so both must be set for output mode.
  *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
  */
 static void
 avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
 {
-#if 0 /* needs more testing -- might be we need two versions for PAL/NTSC */
 	int val = 0;
 
 	if (set) {
 		if (v->mode & VIDEO_SOUND_LANG1)   /* SAP */
-			val = 0xce;
+			val = 0x02;
 		if (v->mode & VIDEO_SOUND_STEREO)
-			val = 0xcd;
+			val = 0x01;
 		if (val) {
-			btaor(val, 0xff, BT848_GPIO_OUT_EN);
-			btaor(val, 0xff, BT848_GPIO_DATA);
+			btaor(val, ~0x03, BT848_GPIO_DATA);
 			if (bttv_gpio)
 				bttv_gpio_tracking(btv,"avermedia");
 		}
@@ -1345,7 +1488,6 @@
 			VIDEO_SOUND_LANG1;
 		return;
 	}
-#endif
 }
 
 static void
@@ -1372,27 +1514,31 @@
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
 
-static struct {
-	char            *name;
-	unsigned short  vendor;
-	unsigned short  device;
-} needs_etbf[] __devinitdata = {
-	{ "Intel 82437FX [Triton PIIX]",
-	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437  },
-	{ "VIA VT82C597 [Apollo VP3]",
-	  PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0 },
-	{ NULL, 0, 0 }
-};
-
 void __devinit bttv_check_chipset(void)
 {
-	int i;
+	int pcipci_fail = 0;
 	struct pci_dev *dev = NULL;
 
-	if(pci_pci_problems & PCIPCI_FAIL)
-		printk(KERN_WARNING "BT848 and your chipset may not work together.\n");
+	/* for 2.4.x we'll use the pci quirks (drivers/pci/quirks.c) */
+	if (pci_pci_problems & PCIPCI_FAIL)
+		pcipci_fail = 1;
+
+	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
+		triton1 = 1;
 
-        while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+	/* print warnings about quirks found */
+	if (triton1)
+		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
+
+	if (pcipci_fail) {
+		printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
+		if (-1 == no_overlay) {
+			printk(KERN_WARNING "bttv: going to disable overlay.\n");
+			no_overlay = 1;
+		}
+	}
+
+	while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
 				      PCI_DEVICE_ID_INTEL_82441, dev))) {
                 unsigned char b;
                 pci_read_config_byte(dev, 0x53, &b);
@@ -1401,11 +1547,6 @@
 			       "bufcon=0x%02x\n",b);
 	}
 
-	if(pci_pci_problems & (PCIPCI_TRITON|PCIPCI_VIAETBF))
-	{
-		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
-		triton1=1;
-	}
 }
 
 int __devinit bttv_handle_chipset(struct bttv *btv)
@@ -1435,24 +1576,6 @@
 	return 0;
 }
 
-
-#ifndef MODULE
-
-static int __init bttv_card_setup(char *str)
-{
-	int i,number,res = 2;
-
-	for (i = 0; res == 2 && i < BTTV_MAX; i++) {
-		res = get_option(&str,&number);
-		if (res)
-			card[i] = number;
-	}
-	return 1;
-}
-
-__setup("bttv_card=", bttv_card_setup);
-
-#endif /* not MODULE */
 
 /*
  * Local variables:
diff -urN linux-2.4.2-pre4/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.4.2-pre4/drivers/media/video/bttv-driver.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/media/video/bttv-driver.c	Mon Dec  3 22:29:16 2001
@@ -253,29 +253,6 @@
 	return 0;
 }
 
-
-/* init + register i2c algo-bit adapter */
-static int __devinit init_bttv_i2c(struct bttv *btv)
-{
-	memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter));
-	memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data));
-	memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client));
-
-	sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name),
-		" #%d", btv->nr);
-        btv->i2c_algo.data = btv;
-        btv->i2c_adap.data = btv;
-        btv->i2c_adap.algo_data = &btv->i2c_algo;
-        btv->i2c_client.adapter = &btv->i2c_adap;
-
-	bttv_bit_setscl(btv,1);
-	bttv_bit_setsda(btv,1);
-
-	btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
-	return btv->i2c_rc;
-}
-
-
 /* ----------------------------------------------------------------------- */
 
 void bttv_gpio_tracking(struct bttv *btv, char *comment)
@@ -1589,8 +1566,10 @@
 		struct video_tuner v;
 		if(copy_from_user(&v,arg,sizeof(v))!=0)
 			return -EFAULT;
+#if 0 /* tuner.signal might be of intrest for non-tuner sources too ... */
 		if(v.tuner||btv->channel)	/* Only tuner 0 */
 			return -EINVAL;
+#endif
 		strcpy(v.name, "Television");
 		v.rangelow=0;
 		v.rangehigh=0xFFFFFFFF;
@@ -1753,6 +1732,8 @@
 			return -EINVAL;
 		if (btv->win.width==0 || btv->win.height==0)
 			return -EINVAL;
+		if (1 == no_overlay)
+			return -EIO;
 		spin_lock_irqsave(&btv->s_lock, irq_flags);
 		if (v == 1 && btv->win.vidadr != 0)
 			btv->scr_on = 1;
@@ -1796,14 +1777,18 @@
 		btv->win.depth=v.depth;
 		btv->win.bpl=v.bytesperline;
 
+#if 0 /* was broken for ages and nobody noticed.  Looks like we don't need
+	 it any more as everybody explicitly sets the palette using VIDIOCSPICT
+	 these days */
 		/* set sefault color format */
-		switch (btv->win.bpp) {
+		switch (v.depth) {
 		case  8: btv->picture.palette = VIDEO_PALETTE_HI240;  break;
 		case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break;
 		case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break;
 		case 24: btv->picture.palette = VIDEO_PALETTE_RGB24;  break;
 		case 32: btv->picture.palette = VIDEO_PALETTE_RGB32;  break;
 		}
+#endif
 	
 		if (bttv_debug)
 			printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
@@ -1833,8 +1818,8 @@
 			return -EFAULT;
 		btv->win.freq=v;
 		bttv_call_i2c_clients(btv,cmd,&v);
-#if 0
-		if (btv->type == BTTV_MIROPRO && btv->radio)
+#if 1
+		if (btv->radio && btv->has_matchbox)
 			tea5757_set_freq(btv,v);
 #endif
 		return 0;
@@ -1882,7 +1867,7 @@
 		
 		/* card specific hooks */
 		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&v,0);
+			bttv_tvcards[btv->type].audio_hook(btv,&v,1);
 
 		btv->audio_dev=v;
 		up(&btv->lock);
@@ -2184,7 +2169,7 @@
 
 static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
-	struct bttv *btv=(struct bttv *)dev;
+	struct bttv *btv=(struct bttv *)(dev-2);
 
 	switch (cmd) {	
 	case VIDIOCGCAP:
@@ -2206,7 +2191,7 @@
 	case VIDIOCGFREQ:
 	case VIDIOCSFREQ:
 	case BTTV_VERSION:
-		return bttv_ioctl(dev,cmd,arg);
+		return bttv_ioctl(dev-2,cmd,arg);
 	case BTTV_VBISIZE:
 		/* make alevt happy :-) */
 		return VBIBUF_SIZE;
@@ -2462,7 +2447,7 @@
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
-	if (radio[btv->nr])
+	if (btv->has_radio)
 	{
 		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
                 {
@@ -2523,6 +2508,7 @@
 
 	btv->errors=0;
 	btv->needs_restart=0;
+	btv->has_radio=radio[btv->nr];
 
 	if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
@@ -2854,11 +2840,11 @@
         if (btv->bt848_mem)
                 iounmap(btv->bt848_mem);
 
-        if(btv->video_dev.minor!=-1)
+        if (btv->video_dev.minor!=-1)
                 video_unregister_device(&btv->video_dev);
-        if(btv->vbi_dev.minor!=-1)
+        if (btv->vbi_dev.minor!=-1)
                 video_unregister_device(&btv->vbi_dev);
-        if (radio[btv->nr] && btv->radio_dev.minor != -1)
+        if (btv->radio_dev.minor != -1)
                 video_unregister_device(&btv->radio_dev);
 
         release_mem_region(pci_resource_start(btv->dev,0),
diff -urN linux-2.4.2-pre4/drivers/media/video/bttv-if.c linux/drivers/media/video/bttv-if.c
--- linux-2.4.2-pre4/drivers/media/video/bttv-if.c	Sun Nov 12 20:47:19 2000
+++ linux/drivers/media/video/bttv-if.c	Mon Dec  3 22:29:16 2001
@@ -36,6 +36,9 @@
 #include "bttvp.h"
 #include "tuner.h"
 
+static struct i2c_algo_bit_data bttv_i2c_algo_template;
+static struct i2c_adapter bttv_i2c_adap_template;
+static struct i2c_client bttv_i2c_client_template;
 
 EXPORT_SYMBOL(bttv_get_cardinfo);
 EXPORT_SYMBOL(bttv_get_id);
@@ -240,17 +243,17 @@
 	}
 }
 
-struct i2c_algo_bit_data bttv_i2c_algo_template = {
+static struct i2c_algo_bit_data bttv_i2c_algo_template = {
 	setsda:  bttv_bit_setsda,
 	setscl:  bttv_bit_setscl,
 	getsda:  bttv_bit_getsda,
 	getscl:  bttv_bit_getscl,
-	udelay:  40,
+	udelay:  16,
 	mdelay:  10,
 	timeout: 200,
 };
 
-struct i2c_adapter bttv_i2c_adap_template = {
+static struct i2c_adapter bttv_i2c_adap_template = {
 	name:              "bt848",
 	id:                I2C_HW_B_BT848,
 	inc_use:           bttv_inc_use,
@@ -259,7 +262,7 @@
 	client_unregister: detach_inform,
 };
 
-struct i2c_client bttv_i2c_client_template = {
+static struct i2c_client bttv_i2c_client_template = {
         name: "bttv internal use only",
         id:   -1,
 };
@@ -323,6 +326,30 @@
 			break;
 		}
 	}
+}
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_bttv_i2c(struct bttv *btv)
+{
+	memcpy(&btv->i2c_adap, &bttv_i2c_adap_template,
+	       sizeof(struct i2c_adapter));
+	memcpy(&btv->i2c_algo, &bttv_i2c_algo_template,
+	       sizeof(struct i2c_algo_bit_data));
+	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
+	       sizeof(struct i2c_client));
+
+	sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name),
+		" #%d", btv->nr);
+        btv->i2c_algo.data = btv;
+        btv->i2c_adap.data = btv;
+        btv->i2c_adap.algo_data = &btv->i2c_algo;
+        btv->i2c_client.adapter = &btv->i2c_adap;
+
+	bttv_bit_setscl(btv,1);
+	bttv_bit_setsda(btv,1);
+
+	btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+	return btv->i2c_rc;
 }
 
 /*
diff -urN linux-2.4.2-pre4/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- linux-2.4.2-pre4/drivers/media/video/bttv.h	Sat Dec 30 11:23:13 2000
+++ linux/drivers/media/video/bttv.h	Mon Dec  3 22:29:16 2001
@@ -57,7 +57,7 @@
 #define BTTV_TYPHOON_TVIEW 0x24
 #define BTTV_PXELVWPLTVPRO 0x25
 #define BTTV_MAGICTVIEW063 0x26
-#define BTTV_PINNACLERAVE  0x27
+#define BTTV_PINNACLE      0x27
 #define BTTV_STB2          0x28
 #define BTTV_AVPHONE98     0x29
 #define BTTV_PV951         0x2a
@@ -70,7 +70,11 @@
 #define BTTV_GVBCTV3PCI    0x31
 #define BTTV_PXELVWPLTVPAK 0x32
 #define BTTV_EAGLE         0x33
-#define BTTV_PINNACLESTUDIO 0x34
+#define BTTV_PINNACLEPRO   0x34
+#define BTTV_TVIEW_RDS_FM  0x35
+#define BTTV_LIVETEC_9415  0x36
+#define BTTV_BESTBUY_EASYTV 0x37
+#define BTTV_FLYVIDEO_98FM 0x38
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -186,15 +190,12 @@
 
 /* i2c */
 #define I2C_CLIENTS_MAX 8
-struct i2c_algo_bit_data bttv_i2c_algo_template;
-struct i2c_adapter bttv_i2c_adap_template;
-struct i2c_client bttv_i2c_client_template;
-void bttv_bit_setscl(void *data, int state);
-void bttv_bit_setsda(void *data, int state);
-void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
-int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
-int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+extern void bttv_bit_setscl(void *data, int state);
+extern void bttv_bit_setsda(void *data, int state);
+extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
+extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
+extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
 	     unsigned char b2, int both);
-void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
+extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
 #endif /* _BTTV_H_ */
diff -urN linux-2.4.2-pre4/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- linux-2.4.2-pre4/drivers/media/video/bttvp.h	Sat Dec 30 11:23:13 2000
+++ linux/drivers/media/video/bttvp.h	Mon Dec  3 22:29:16 2001
@@ -25,7 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,50)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,57)
 
 
 #include <linux/types.h>
@@ -43,10 +43,14 @@
 /* bttv-driver.c                                              */
 
 /* insmod options / kernel args */
+extern int no_overlay;
 extern unsigned int bttv_verbose;
 extern unsigned int bttv_debug;
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
+extern int init_bttv_i2c(struct bttv *btv);
+
+#define dprintk		if (bttv_debug) printk
 
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
@@ -143,6 +147,16 @@
 	int audio;           /* audio mode */
 	int audio_chip;      /* set to one of the chips supported by bttv.c */
 	int radio;
+	int has_radio;
+
+	/* miro/pinnacle + Aimslab VHX
+	   philips matchbox (tea5757 radio tuner) support */
+	int has_matchbox;
+	int mbox_we;
+	int mbox_data;
+	int mbox_clk;
+	int mbox_most;
+	int mbox_mask;
 
 	u32 *risc_jmp;
 	u32 *vbi_odd;
diff -urN linux-2.4.2-pre4/drivers/media/video/cpia_usb.c linux/drivers/media/video/cpia_usb.c
--- linux-2.4.2-pre4/drivers/media/video/cpia_usb.c	Thu Jan  4 13:15:32 2001
+++ linux/drivers/media/video/cpia_usb.c	Mon Dec  3 22:29:16 2001
@@ -558,6 +558,7 @@
 
 static struct usb_device_id cpia_id_table [] = {
 	{ USB_DEVICE(0x0553, 0x0002) },
+	{ USB_DEVICE(0x0813, 0x0001) },
 	{ }					/* Terminating entry */
 };
 
diff -urN linux-2.4.2-pre4/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c
--- linux-2.4.2-pre4/drivers/media/video/msp3400.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/media/video/msp3400.c	Mon Dec  3 22:29:16 2001
@@ -90,6 +90,7 @@
 	int nicam_on;
 	int acb;
 	int main, second;	/* sound carrier */
+	int scart;              /* input is scart */
 
 	int muted;
 	int left, right;	/* volume */
@@ -733,6 +734,8 @@
 
 		if (VIDEO_MODE_RADIO == msp->norm)
 			continue;  /* nothing to do */
+		if (msp->scart)
+			continue;  /* nothing to do */
 	
 		msp->active = 1;
 
@@ -749,6 +752,10 @@
 			goto done;
 		
 	restart:
+		if (msp->scart)
+			continue;
+		if (VIDEO_MODE_RADIO == msp->norm)
+			continue;
 		msp->restart = 0;
 		msp3400c_setvolume(client, msp->muted, 0, 0);
 		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
@@ -912,7 +919,7 @@
 	msp->thread = NULL;
 
 	if(msp->notify != NULL)
-		up_and_exit(msp->notify, 0);
+		up(msp->notify);
 	return 0;
 }
 
@@ -982,6 +989,9 @@
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
+		if (msp->scart)
+			continue;
+		
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
@@ -997,6 +1007,8 @@
 			goto done;
 
 	restart:
+		if (msp->scart)
+			continue;
 		msp->restart = 0;
 		del_timer(&msp->wake_stereo);
 		msp->watch_stereo = 0;
@@ -1004,11 +1016,6 @@
 		/* put into sane state (and mute) */
 		msp3400c_reset(client);
 
-		/* set various prescales */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
-
 		/* start autodetect */
 		switch (msp->norm) {
 		case VIDEO_MODE_PAL:
@@ -1081,6 +1088,11 @@
 			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
 		}
 
+		/* set various prescales */
+		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
+		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
+		msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
+
 		/* set stereo */
 		switch (val) {
 		case 0x0008: /* B/G NICAM */
@@ -1320,19 +1332,25 @@
 
 	case AUDC_SET_INPUT:
 #if 1
+		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
 		/* hauppauge 44xxx scart switching */
+		msp->scart = 0;
 		switch (*sarg) {
 		case AUDIO_RADIO:
 			msp3400c_set_scart(client,SCART_IN2,0);
 			break;
 		case AUDIO_EXTERN:
+			msp->scart   = 1;
 			msp3400c_set_scart(client,SCART_IN1,0);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x0008,0x0220);
 			break;
 		default:
 			if (*sarg & AUDIO_MUTE)
 				msp3400c_set_scart(client,SCART_MUTE,0);
 			break;
 		}
+		if (msp->active)
+			msp->restart = 1;
 #endif
 		break;
 
@@ -1344,8 +1362,6 @@
 		if (msp->simple) {
 			/* the thread will do for us */
 			msp3400c_setvolume(client,msp->muted,0,0);
-			if (msp->active)
-				msp->restart = 1;
 			wake_up_interruptible(&msp->wq);
 		} else {
 			/* set msp3400 to FM radio mode */
@@ -1353,6 +1369,8 @@
 			msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
 			msp3400c_setvolume(client,msp->muted,msp->left,msp->right);			
 		}
+		if (msp->active)
+			msp->restart = 1;
 		break;
 
 	/* --- v4l ioctls --- */
diff -urN linux-2.4.2-pre4/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c
--- linux-2.4.2-pre4/drivers/media/video/tuner.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/media/video/tuner.c	Mon Dec  3 22:29:16 2001
@@ -34,6 +34,7 @@
 static int type  = -1; /* insmod parameter */
 
 static int addr  =  0;
+static char *pal =  "b";
 static int this_adap;
 
 #define dprintk     if (debug) printk
@@ -41,6 +42,7 @@
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
+MODULE_PARM(pal,"s");
 
 struct tuner
 {
@@ -55,6 +57,44 @@
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
+/* tv standard selection for Temic 4046 FM5
+   this value takes the low bits of control byte 2
+   from datasheet Rev.01, Feb.00 
+     standard     BG      I       L       L2      D
+     picture IF   38.9    38.9    38.9    33.95   38.9
+     sound 1      33.4    32.9    32.4    40.45   32.4
+     sound 2      33.16   
+     NICAM        33.05   32.348  33.05           33.05
+ */
+#define TEMIC_SET_PAL_I         0x05
+#define TEMIC_SET_PAL_DK        0x09
+#define TEMIC_SET_PAL_L         0x0a // SECAM ?
+#define TEMIC_SET_PAL_L2        0x0b // change IF !
+#define TEMIC_SET_PAL_BG        0x0c
+
+/* tv tuner system standard selection for Philips FQ1216ME
+   this value takes the low bits of control byte 2
+   from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
+     standard 		BG	DK	I	L	L`
+     picture carrier	38.90	38.90	38.90	38.90	33.95
+     colour		34.47	34.47	34.47	34.47	38.38
+     sound 1		33.40	32.40	32.90	32.40	40.45
+     sound 2		33.16	-	-	-	-
+     NICAM		33.05	33.05	32.35	33.05	39.80
+ */
+#define PHILIPS_SET_PAL_I	0x01 /* Bit 2 always zero !*/
+#define PHILIPS_SET_PAL_BGDK	0x09
+#define PHILIPS_SET_PAL_L2	0x0a
+#define PHILIPS_SET_PAL_L	0x0b	
+
+/* system switching for Philips FI1216MF MK2
+   from datasheet "1996 Jul 09",
+ */
+#define PHILIPS_MF_SET_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_PAL_L	0x03
+#define PHILIPS_MF_SET_PAL_L2	0x02
+
+
 /* ---------------------------------------------------------------------- */
 
 struct tunertype 
@@ -63,18 +103,13 @@
 	unsigned char Vendor;
 	unsigned char Type;
   
-	unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */   
-	unsigned short thresh2;  
+	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
+	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
 	unsigned char VHF_L;
 	unsigned char VHF_H;
 	unsigned char UHF;
 	unsigned char config; 
-	unsigned short IFPCoff;
-	unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */
-			/* 0x01 -> ??? no change ??? */
-			/* 0x02 -> PAL BDGHI / SECAM L */
-			/* 0x04 -> ??? PAL others / SECAM others ??? */
-	int capability;
+	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 732=16*45.75 NTSC */
 };
 
 /*
@@ -83,23 +118,25 @@
  *	"no float in kernel" rule.
  */
 static struct tunertype tuners[] = {
-        { "Temic PAL", TEMIC, PAL,
+        { "Temic PAL (4002 FH5)", TEMIC, PAL,
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
 	{ "Philips PAL_I", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
 	{ "Philips NTSC", Philips, NTSC,
 	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
 	{ "Philips SECAM", Philips, SECAM,
-	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02},
+	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
+
 	{ "NoTuner", NoTuner, NOTUNER,
-	  0,0,0x00,0x00,0x00,0x00,0x00,000},
+	  0,0,0x00,0x00,0x00,0x00,0x00},
 	{ "Philips PAL", Philips, PAL,
 	  16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
-	{ "Temic NTSC", TEMIC, NTSC,
+	{ "Temic NTSC (4032 FY5)", TEMIC, NTSC,
 	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
-	{ "Temic PAL_I", TEMIC, PAL_I,
+	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
 	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
- 	{ "Temic 4036 FY5 NTSC", TEMIC, NTSC,
+
+ 	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
 	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
         { "Alps HSBH1", TEMIC, NTSC,
 	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
@@ -107,14 +144,36 @@
 	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
         { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
+
         { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
         { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
-	{ "Temic 4006FH5", TEMIC, PAL_I,
+	{ "Temic PAL_I (4006FH5)", TEMIC, PAL_I,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
   	{ "Alps TSCH6",Alps,NTSC,
   	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+
+  	{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL,
+  	  16*136.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+  	{ "Philips NTSC_M (MK2)",Philips,NTSC,
+  	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+
+        { "Temic PAL (4009 FR5)", TEMIC, PAL,
+          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+        { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+        { "Philips PAL_DK", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+
+	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -165,6 +224,7 @@
 }
 #endif
 
+// Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
 static void set_tv_freq(struct i2c_client *c, int freq)
 {
 	u8 config;
@@ -174,6 +234,15 @@
         unsigned char buffer[4];
 	int rc;
 
+	if (freq < 45*16 || freq > 890*16) {
+		/* FIXME: better do that chip-specific, but
+		   right now we don't have that in the config
+		   struct and this way is still better than no
+		   check at all */
+		printk("tuner: TV freq out of range\n");
+		return;
+	}
+
 	if (t->type == -1) {
 		printk("tuner: tuner type not set\n");
 		return;
@@ -187,32 +256,81 @@
 	else
 		config = tun->UHF;
 
-#if 1   // Fix colorstandard mode change
-	if (t->type == TUNER_PHILIPS_SECAM && t->mode)
-		config |= tun->mode;
-	else
-		config &= ~tun->mode;
-#else
-		config &= ~tun->mode;
-#endif
 
-	div=freq + tun->IFPCoff;
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (t->type) {
+	case TUNER_PHILIPS_SECAM:
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		config &= ~0x02;
+		if (t->mode)
+			config |= 0x02;
+		break;
 
-    /*
-     * Philips FI1216MK2 remark from specification :
-     * for channel selection involving band switching, and to ensure
-     * smooth tuning to the desired channel without causing
-     * unnecessary charge pump action, it is recommended to consider
-     * the difference between wanted channel frequency and the
-     * current channel frequency.  Unnecessary charge pump action
-     * will result in very low tuning voltage which may drive the
-     * oscillator to extreme conditions.
-     */
-    /*
-     * Progfou: specification says to send config data before
-     * frequency in case (wanted frequency < current frequency).
-     */
+	case TUNER_TEMIC_4046FM5:
+		config &= ~0x0f;
+		switch (pal[0]) {
+		case 'i':
+		case 'I':
+			config |= TEMIC_SET_PAL_I;
+			break;
+		case 'd':
+		case 'D':
+			config |= TEMIC_SET_PAL_DK;
+			break;
+		case 'l':
+		case 'L':
+			config |= TEMIC_SET_PAL_L;
+			break;
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		default:
+			config |= TEMIC_SET_PAL_BG;
+			break;
+		break;
+		}
+	case TUNER_PHILIPS_FQ1216ME:
+		config &= ~0x0f;
+		switch (pal[0]) {
+		case 'i':
+		case 'I':
+			config |= PHILIPS_SET_PAL_I;
+			break;
+		case 'l':
+		case 'L':
+			config |= PHILIPS_SET_PAL_L;
+			break;
+		case 'd':
+		case 'D':
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+			config |= PHILIPS_SET_PAL_BGDK;
+			break;
+		break;
+		}
+	}
 
+	
+	/*
+	 * Philips FI1216MK2 remark from specification :
+	 * for channel selection involving band switching, and to ensure
+	 * smooth tuning to the desired channel without causing
+	 * unnecessary charge pump action, it is recommended to consider
+	 * the difference between wanted channel frequency and the
+	 * current channel frequency.  Unnecessary charge pump action
+	 * will result in very low tuning voltage which may drive the
+	 * oscillator to extreme conditions.
+	 *
+	 * Progfou: specification says to send config data before
+	 * frequency in case (wanted frequency < current frequency).
+	 */
+
+	div=freq + tun->IFPCoff;
 	if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
 		buffer[0] = tun->config;
 		buffer[1] = config;
@@ -239,6 +357,10 @@
         unsigned char buffer[4];
 	int rc;
 
+	if (freq < 76*16 || freq > 108*16) {
+		printk("tuner: radio freq out of range\n");
+		return;
+	}
 	if (t->type == -1) {
 		printk("tuner: tuner type not set\n");
 		return;
@@ -378,16 +500,16 @@
 	{
 		unsigned long *v = arg;
 
-		t->freq = *v;
 		if (t->radio) {
 			dprintk("tuner: radio freq set to %d.%02d\n",
 				(*iarg)/16,(*iarg)%16*100/16);
-			set_radio_freq(client,t->freq);
+			set_radio_freq(client,*v);
 		} else {
 			dprintk("tuner: tv freq set to %d.%02d\n",
 				(*iarg)/16,(*iarg)%16*100/16);
-			set_tv_freq(client,t->freq);
+			set_tv_freq(client,*v);
 		}
+		t->freq = *v;
 		return 0;
 	}
 	case VIDIOCGTUNER:
diff -urN linux-2.4.2-pre4/drivers/media/video/tuner.h linux/drivers/media/video/tuner.h
--- linux-2.4.2-pre4/drivers/media/video/tuner.h	Sun Nov 12 20:47:19 2000
+++ linux/drivers/media/video/tuner.h	Mon Dec  3 22:29:16 2001
@@ -22,22 +22,32 @@
 #ifndef _TUNER_H
 #define _TUNER_H
 
-#define TUNER_TEMIC_PAL     0  /*  Miro Gpio Coding -1 */
+#define TUNER_TEMIC_PAL     0        /* 4002 FH5_9483 */
 #define TUNER_PHILIPS_PAL_I 1
 #define TUNER_PHILIPS_NTSC  2
-#define TUNER_PHILIPS_SECAM 3
+#define TUNER_PHILIPS_SECAM 3		/* you must actively select B/G, L, L` */
 #define TUNER_ABSENT        4
 #define TUNER_PHILIPS_PAL   5
-#define TUNER_TEMIC_NTSC    6
-#define TUNER_TEMIC_PAL_I   7
-#define TUNER_TEMIC_4036FY5_NTSC	8
-#define TUNER_ALPS_TSBH1_NTSC 	9
+#define TUNER_TEMIC_NTSC    6        /* 4032 FY5_7004 */
+#define TUNER_TEMIC_PAL_I   7        /* 4062 FY5_9957 */
+#define TUNER_TEMIC_4036FY5_NTSC 8   /* 4036 FY5      */
+#define TUNER_ALPS_TSBH1_NTSC 	 9
 #define TUNER_ALPS_TSBE1_PAL 	10
 #define TUNER_ALPS_TSBB5_PAL_I 	11
 #define TUNER_ALPS_TSBE5_PAL 	12
 #define TUNER_ALPS_TSBC5_PAL 	13
-#define TUNER_TEMIC_4006FH5_PAL	14
+#define TUNER_TEMIC_4006FH5_PAL	14   /* 4006 FH5      */
 #define TUNER_ALPS_TSHC6_NTSC 	15
+#define TUNER_TEMIC_PAL_DK	16   /* 4016 FY5      */
+#define TUNER_PHILIPS_NTSC_M	17
+#define TUNER_TEMIC_4066FY5_PAL_I       18
+#define TUNER_TEMIC_4006FN5_MULTI_PAL   19  /* B/G, I and D/K autodetected */
+#define TUNER_TEMIC_4009FR5_PAL         20  /* incl. FM radio */
+#define TUNER_TEMIC_4039FR5_NTSC        21  /* incl. FM radio */
+#define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  */
+#define TUNER_PHILIPS_PAL_DK		23
+#define TUNER_PHILIPS_FQ1216ME		24  /* you must actively select B/G/D/K, I, L, L` */
+
 
 #define NOTUNER 0
 #define PAL     1
diff -urN linux-2.4.2-pre4/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c
--- linux-2.4.2-pre4/drivers/media/video/tvaudio.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/media/video/tvaudio.c	Mon Dec  3 22:29:16 2001
@@ -112,13 +112,14 @@
 	audiocmd   shadow;
 
 	/* current settings */
-	__u16 left,right,treble,bass;
+	__u16 left,right,treble,bass,mode;
 
 	/* thread */
 	struct task_struct  *thread;
 	struct semaphore    *notify;
 	wait_queue_head_t    wq;
-	int                  wake,done;
+	struct timer_list    wt;
+	int                  done;
 };
 
 
@@ -245,6 +246,12 @@
  *   if available, ...
  */
 
+static void chip_thread_wake(unsigned long data)
+{
+        struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
+	wake_up_interruptible(&chip->wq);
+}
+
 static int chip_thread(void *data)
 {
         struct CHIPSTATE *chip = data;
@@ -266,37 +273,44 @@
 		up(chip->notify);
 
 	for (;;) {
-		if (chip->done)
-			break;
-		if (!chip->wake) {
-			interruptible_sleep_on(&chip->wq);
-			dprintk("%s: thread wakeup\n", chip->c.name);
-			if (chip->done || signal_pending(current))
-				break;
-		}
-		chip->wake = 0;
-
-		/* wait some time -- let the audio hardware
-		   figure the current mode */
-		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ);
-		if (signal_pending(current))
+		interruptible_sleep_on(&chip->wq);
+		dprintk("%s: thread wakeup\n", chip->c.name);
+		if (chip->done || signal_pending(current))
 			break;
-		if (chip->wake)
+		
+		if (0 != chip->mode)
+			/* don't do anything if mode != auto */
 			continue;
-
+		
+		/* have a look what's going on */
 		dprintk("%s: thread checkmode\n", chip->c.name);
 		desc->checkmode(chip);
+		
+		/* schedule next check */
+		mod_timer(&chip->wt, jiffies+2*HZ);
 	}
 
 	chip->thread = NULL;
 	dprintk("%s: thread exiting\n", chip->c.name);
 	if(chip->notify != NULL)
-		up_and_exit(chip->notify,0);
+		up(chip->notify);
 
 	return 0;
 }
 
+void generic_checkmode(struct CHIPSTATE *chip)
+{
+	struct CHIPDESC  *desc = chiplist + chip->type;
+	int mode = desc->getmode(chip);
+
+	if (mode & VIDEO_SOUND_STEREO)
+		desc->setmode(chip,VIDEO_SOUND_STEREO);
+	else if (mode & VIDEO_SOUND_LANG1)
+		desc->setmode(chip,VIDEO_SOUND_LANG1);
+	else
+		desc->setmode(chip,VIDEO_SOUND_MONO);
+}
+
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - defines+functions for tda9840                */
 
@@ -313,10 +327,24 @@
 #define TDA9840_DUALBA     0x16
 #define TDA9840_EXTERNAL   0x7a
 
+#define TDA9840_DS_DUAL    0x20 /* Dual sound identified          */
+#define TDA9840_ST_STEREO  0x40 /* Stereo sound identified        */
+#define TDA9840_PONRES     0x80 /* Power-on reset detected if = 1 */
+
 int  tda9840_getmode(struct CHIPSTATE *chip)
 {
-	return VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-		VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	int val, mode;
+	
+	val = chip_read(chip);
+	mode = VIDEO_SOUND_MONO;
+	if (val & TDA9840_DS_DUAL)
+		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	if (val & TDA9840_ST_STEREO)
+		mode |= VIDEO_SOUND_STEREO;
+	
+	dprintk ("tda9840_getmode(): raw chip read: %d, return: %d\n",
+		 val, mode);
+	return mode;
 }
 
 void tda9840_setmode(struct CHIPSTATE *chip, int mode)
@@ -617,6 +645,12 @@
 {
 	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & 0xe3;
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+
+	if (sw_data & 3) {
+		dprintk("tda9873_setmode(): external input\n");
+		return;
+	}
+	
 	dprintk("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
 	dprintk("tda9873_setmode(): sw_data  = %d\n", sw_data);
 
@@ -638,16 +672,6 @@
 	chip_write(chip,TDA9873_SW,sw_data);
 }
 
-void tda9873_checkmode(struct CHIPSTATE *chip)
-{
-	int mode = tda9873_getmode(chip);
-
-	if (mode & VIDEO_SOUND_STEREO)
-		tda9873_setmode(chip,VIDEO_SOUND_STEREO);
-	if (mode & VIDEO_SOUND_LANG1)
-		tda9873_setmode(chip,VIDEO_SOUND_LANG1);
-}
-
 int tda9873_checkit(struct CHIPSTATE *chip)
 {
 	int rc;
@@ -751,6 +775,7 @@
 
 		getmode:    tda9840_getmode,
 		setmode:    tda9840_setmode,
+		checkmode:  generic_checkmode,
 
 		init:       { 2, { TDA9840_SW, 0x2a } }
 	},
@@ -762,12 +787,17 @@
 		addr_lo:    I2C_TDA985x_L >> 1,
 		addr_hi:    I2C_TDA985x_H >> 1,
 		registers:  3,
+		flags:      CHIP_HAS_INPUTSEL,
 
 		getmode:    tda9873_getmode,
 		setmode:    tda9873_setmode,
-		checkmode:  tda9873_checkmode,
+		checkmode:  generic_checkmode,
 
-		init:       { 4, { TDA9873_SW, 0xa0, 0x06, 0x03 } }
+		init:       { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
+		inputreg:   TDA9873_SW,
+		inputmute:  0xc0,
+		inputmap:   {0xa4, 0xa2, 0xa4, 0xa4, 0xc0}
+		
 	},
 	{
 		name:       "tda9850",
@@ -873,7 +903,10 @@
 
 		inputreg:   PIC16C54_REG_MISC,
 		inputmap:   {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
-			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE},
+			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
+			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
+			     PIC16C54_MISC_SND_MUTE,PIC16C54_MISC_SND_MUTE,
+			     PIC16C54_MISC_SND_NOTMUTE},
 		inputmute:  PIC16C54_MISC_SND_MUTE,
 	},
 	{ name: NULL } /* EOF */
@@ -947,11 +980,12 @@
 		/* start async thread */
 		DECLARE_MUTEX_LOCKED(sem);
 		chip->notify = &sem;
+		chip->wt.function = chip_thread_wake;
+		chip->wt.data     = (unsigned long)chip;
 		init_waitqueue_head(&chip->wq);
 		kernel_thread(chip_thread,(void *)chip,0);
 		down(&sem);
 		chip->notify = NULL;
-		chip->wake++;
 		wake_up_interruptible(&chip->wq);
 	}
 	return 0;
@@ -1048,17 +1082,19 @@
 			chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
 			chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
 		}
-		if (desc->setmode && va->mode)
+		if (desc->setmode && va->mode) {
+			chip->mode = va->mode;
 			desc->setmode(chip,va->mode);
+		}
 		break;
 	}
 	case VIDIOCSFREQ:
 	{
+		chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
 			desc->setmode(chip,VIDEO_SOUND_MONO);
-			chip->wake++;
-			wake_up_interruptible(&chip->wq);
-			/* the thread will call checkmode() a second later */
+			mod_timer(&chip->wt, jiffies+2*HZ);
+			/* the thread will call checkmode() later */
 		}
 	}
 	}
diff -urN linux-2.4.2-pre4/drivers/mtd/octagon-5066.c linux/drivers/mtd/octagon-5066.c
--- linux-2.4.2-pre4/drivers/mtd/octagon-5066.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/mtd/octagon-5066.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.12 2000/11/27 08:50:22 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.12.2.1 2001/02/15 10:12:48 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -273,7 +273,7 @@
 		}
 	}
 	
-	if (!oct5066_mtd[1] && !oct5066_mtd[2]) {
+	if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
 		cleanup_oct5066();
 		return -ENXIO;
 	}	  
diff -urN linux-2.4.2-pre4/drivers/mtd/pmc551.c linux/drivers/mtd/pmc551.c
--- linux-2.4.2-pre4/drivers/mtd/pmc551.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/mtd/pmc551.c	Mon Dec  3 22:29:16 2001
@@ -483,7 +483,7 @@
         pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
 
         /*
-         * Wait untill command has gone through
+         * Wait until command has gone through
          * FIXME: register spinning issue
          */
         do {	pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
@@ -709,7 +709,7 @@
                        PCI_Device->irq);
 
                 /*
-                 * The PMC551 device acts VERY wierd if you don't init it
+                 * The PMC551 device acts VERY weird if you don't init it
                  * first.  i.e. it will not correctly report devsel.  If for
                  * some reason the sdram is in a wrote-protected state the
                  * device will DEVSEL when it is written to causing problems
diff -urN linux-2.4.2-pre4/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- linux-2.4.2-pre4/drivers/net/ewrk3.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/ewrk3.c	Mon Dec  3 22:29:16 2001
@@ -136,7 +136,6 @@
    =========================================================================
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in
--- linux-2.4.2-pre4/drivers/net/tokenring/Config.in	Thu Mar 30 16:54:53 2000
+++ linux/drivers/net/tokenring/Config.in	Mon Dec  3 22:29:16 2001
@@ -13,6 +13,7 @@
    dep_tristate '  Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR
    if [ "$CONFIG_TMS380TR" != "n" ]; then
       dep_tristate '    Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR
+      dep_tristate '    Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_TMS380TR
       dep_tristate '    Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR
       if [ "$CONFIG_MCA" = "y" ]; then 
          dep_tristate '    Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/Makefile linux/drivers/net/tokenring/Makefile
--- linux-2.4.2-pre4/drivers/net/tokenring/Makefile	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/Makefile	Mon Dec  3 22:29:16 2001
@@ -19,6 +19,7 @@
 obj-$(CONFIG_ABYSS) 	+= abyss.o
 obj-$(CONFIG_MADGEMC) 	+= madgemc.o
 obj-$(CONFIG_TMSPCI) 	+= tmspci.o
+obj-$(CONFIG_TMSISA) 	+= tmsisa.o
 obj-$(CONFIG_SMCTR) 	+= smctr.o
 
 O_TARGET := tr.o
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/abyss.c linux/drivers/net/tokenring/abyss.c
--- linux-2.4.2-pre4/drivers/net/tokenring/abyss.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/abyss.c	Mon Dec  3 22:29:16 2001
@@ -137,7 +137,8 @@
 	 */
 	dev->base_addr += 0x10;
 		
-	ret = tmsdev_init(dev);
+	ret = tmsdev_init(dev,0,pdev);
+	/* XXX: should be the max PCI32 DMA max */
 	if (ret) {
 		printk("%s: unable to get memory for dev->priv.\n", 
 		       dev->name);
@@ -153,7 +154,6 @@
 	printk("\n");
 
 	tp = dev->priv;
-	tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
 	tp->setnselout = abyss_setnselout_pins;
 	tp->sifreadb = abyss_sifreadb;
 	tp->sifreadw = abyss_sifreadw;
@@ -173,7 +173,7 @@
 	return 0;
 
 err_out_tmsdev:
-	kfree(dev->priv);
+	tmsdev_term(dev);
 err_out_irq:
 	free_irq(pdev->irq, dev);
 err_out_region:
@@ -441,7 +441,7 @@
 	unregister_netdev(dev);
 	release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT);
 	free_irq(dev->irq, dev);
-	kfree(dev->priv);
+	tmsdev_term(dev);
 	kfree(dev);
 	pci_set_drvdata(pdev, NULL);
 }
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.2-pre4/drivers/net/tokenring/lanstreamer.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/lanstreamer.c	Mon Dec  3 22:29:16 2001
@@ -237,6 +237,7 @@
 				printk(KERN_ERR "lanstreamer: out of memory.\n");
 				break;
 			}
+			SET_MODULE_OWNER(dev);
 #endif
 			dev->priv = (void *) streamer_priv;
 #if STREAMER_DEBUG
@@ -736,7 +737,6 @@
 #endif
 
 	netif_start_queue(dev);
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -907,7 +907,7 @@
 				streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len;
 				streamer_priv->streamer_stats.tx_packets++;
 				dev_kfree_skb_irq(streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]);
-				streamer_priv-> streamer_tx_ring[streamer_priv->tx_ring_last_status].buffer = 0xdeadbeef;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buffer = 0xdeadbeef;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0;
@@ -1071,8 +1071,6 @@
 	printk("\n");
 #endif
 	free_irq(dev->irq, dev);
-
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1384,8 +1382,11 @@
 			       status, len);
 		}
 #endif
-		mac_frame = dev_alloc_skb(frame_len);
-
+		if (!(mac_frame = dev_alloc_skb(frame_len))) {
+			printk(KERN_WARNING "%s: Memory squeeze, dropping frame.\n",
+			       dev->name);
+			goto drop_frame;
+		}
 		/* Walk the buffer chain, creating the frame */
 
 		do {
@@ -1432,7 +1433,7 @@
 		netif_rx(mac_frame);
 
 		/* Now tell the card we have dealt with the received frame */
-
+drop_frame:
 		/* Set LISR Bit 1 */
 		writel(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM);
 
@@ -1759,6 +1760,7 @@
 	{
 		dev_streamer[i] = NULL;
 		dev_streamer[i] = init_trdev(dev_streamer[i], 0);
+		SET_MODULE_OWNER(dev_streamer[i]);
 		if (dev_streamer[i] == NULL)
 			return -ENOMEM;
 
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/madgemc.c linux/drivers/net/tokenring/madgemc.c
--- linux-2.4.2-pre4/drivers/net/tokenring/madgemc.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/madgemc.c	Mon Dec  3 22:29:16 2001
@@ -349,7 +349,7 @@
 			printk(":%2.2x", dev->dev_addr[i]);
 		printk("\n");
 
-		if (tmsdev_init(dev)) {
+		if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) {
 			printk("%s: unable to get memory for dev->priv.\n", 
 			       dev->name);
 			return -1;
@@ -362,7 +362,6 @@
 		 * they know what they're talking about.  Cut off DMA
 		 * at 16mb.
 		 */
-		tp->dmalimit = ISA_MAX_ADDRESS; /* XXX: ?? */
 		tp->setnselout = madgemc_setnselout_pins;
 		tp->sifwriteb = madgemc_sifwriteb;
 		tp->sifreadb = madgemc_sifreadb;
@@ -383,7 +382,7 @@
 			printk("madgemc: register_trdev() returned non-zero.\n");
 			
 			kfree(card);
-			kfree(dev->priv);
+			tmsdev_term(dev);
 			kfree(dev);
 			return -1;
 		}
@@ -783,7 +782,7 @@
 		unregister_trdev(dev);
 		release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT);
 		free_irq(dev->irq, dev);
-		kfree(dev->priv);
+		tmsdev_term(dev);
 		kfree(dev);
 		this_card = madgemc_card_list;
 		madgemc_card_list = this_card->next;
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- linux-2.4.2-pre4/drivers/net/tokenring/smctr.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/smctr.c	Mon Dec  3 22:29:16 2001
@@ -1348,7 +1348,7 @@
          * Make sure the mem_used offset at this point is the
          * same as in allocate_shared memory or the following
          * boundry adjustment will be incorrect (i.e. not allocating
-         * the non-mac recieve buffers above cannot change the 256
+         * the non-mac receive buffers above cannot change the 256
          * byte offset).
          *
          * Since this cannot be guaranteed, adding the full 256 bytes
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
--- linux-2.4.2-pre4/drivers/net/tokenring/tms380tr.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/tms380tr.c	Mon Dec  3 22:29:16 2001
@@ -13,13 +13,7 @@
  *  The following modules are currently available for card support:
  *	- tmspci (Generic PCI card support)
  *	- abyss (Madge PCI support)
- *  
- *  The following cards are currently lacking support, even
- *  though they were supported in previous versions, because
- *  their code did not get migrated into a seperate module:
- *	- SysKonnect TR4/16(+) ISA	(SK-4190)
- *  They are no longer supported by this driver, at least until
- *  a module gets written for them.
+ *      - tmsisa (SysKonnect TR4/16 ISA)
  *
  *  Sources:
  *  	- The hardware related parts of this driver are take from
@@ -38,6 +32,7 @@
  *    CG	Christoph Goos		cgoos@syskonnect.de
  *    AF	Adam Fritzler		mid@auk.cx
  *    MLP       Mike Phillips           phillim@amtrak.com
+ *    JF	Jochen Friedrich	jochen@scram.de
  *     
  *  Modification History:
  *	29-Aug-97	CG	Created
@@ -57,10 +52,15 @@
  *	30-Dec-99	AF	Turned tms380tr into a library ala 8390.
  *				Madge support is provided in the abyss module
  *				Generic PCI support is in the tmspci module.
- *
+ *	30-Nov-00	JF	Updated PCI code to support IO MMU via
+ *				pci_map_static(). Alpha uses this MMU for ISA
+ *				as well.
+ *      14-Jan-01	JF	Fix DMA on ifdown/ifup sequences. Some 
+ *      			cleanup.
+ *      			
  *  To do:
  *    1. Multi/Broadcast packet handling (this may have fixed itself)
- *    2. Write a sktrisa module that includes the old ISA support
+ *    2. Write a sktrisa module that includes the old ISA support (done)
  *    3. Allow modules to load their own microcode
  *    4. Speed up the BUD process -- freezing the kernel for 3+sec is
  *         quite unacceptable.
@@ -68,7 +68,7 @@
  */
 
 #ifdef MODULE
-static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Adam Fritzler\n";
+static const char *version = "tms380tr.c: v1.08 14/01/2001 by Christoph Goos, Adam Fritzler\n";
 #endif
 
 #ifdef MODULE
@@ -125,9 +125,6 @@
 static void	tms380tr_cancel_tx_queue(struct net_local* tp);
 static int 	tms380tr_chipset_init(struct net_device *dev);
 static void 	tms380tr_chk_irq(struct net_device *dev);
-#if 0
-static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr);
-#endif
 static void 	tms380tr_chk_outstanding_cmds(struct net_device *dev);
 static void 	tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);
 static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType);
@@ -191,7 +188,7 @@
 
 
 
-#if TMS380TR_DEBUG > 0
+#if 0 /* TMS380TR_DEBUG > 0 */
 static int madgemc_sifprobe(struct net_device *dev)
 {
         unsigned char old, chk1, chk2;
@@ -259,6 +256,16 @@
 	int err;
 	
 	/* Reset the hardware here. Don't forget to set the station address. */
+
+	if(dev->dma > 0) 
+	{
+		unsigned long flags=claim_dma_lock();
+		disable_dma(dev->dma);
+		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+		enable_dma(dev->dma);
+		release_dma_lock(flags);
+	}
+	
 	err = tms380tr_chipset_init(dev);
   	if(err)
 	{
@@ -275,6 +282,7 @@
 
 	printk(KERN_INFO "%s: Adapter RAM size: %dK\n", 
 	       dev->name, tms380tr_read_ptr(dev));
+
 	tms380tr_enable_interrupts(dev);
 	tms380tr_open_adapter(dev);
 
@@ -334,18 +342,26 @@
 	tms380tr_init_opb(dev);
 	tms380tr_init_net_local(dev);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Resetting adapter...\n", dev->name);
 	err = tms380tr_reset_adapter(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Bringup diags...\n", dev->name);
 	err = tms380tr_bringup_diags(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Init adapter...\n", dev->name);
 	err = tms380tr_init_adapter(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Done!\n", dev->name);
 	return (0);
 }
 
@@ -356,6 +372,7 @@
 {
 	struct net_local *tp = (struct net_local *)dev->priv;
 	int i;
+	dma_addr_t dmabuf;
 
 	tp->scb.CMD	= 0;
 	tp->scb.Parm[0] = 0;
@@ -381,11 +398,11 @@
 
 	skb_queue_head_init(&tp->SendSkbQueue);
 	tp->QueueSkb = MAX_TX_QUEUE;
-	
+
 	/* Create circular chain of transmit lists */
 	for (i = 0; i < TPL_NUM; i++)
 	{
-		tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));
+		tp->Tpl[i].NextTPLAddr = htonl(((char *)(&tp->Tpl[(i+1) % TPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */
 		tp->Tpl[i].Status	= 0;
 		tp->Tpl[i].FrameSize	= 0;
 		tp->Tpl[i].FragList[0].DataCount	= 0;
@@ -393,6 +410,7 @@
 		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];
 		tp->Tpl[i].MData	= NULL;
 		tp->Tpl[i].TPLIndex	= i;
+		tp->Tpl[i].DMABuff	= 0;
 		tp->Tpl[i].BusyFlag	= 0;
 	}
 
@@ -401,19 +419,20 @@
 	/* Create circular chain of receive lists */
 	for (i = 0; i < RPL_NUM; i++)
 	{
-		tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));
+		tp->Rpl[i].NextRPLAddr = htonl(((char *)(&tp->Rpl[(i+1) % RPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */
 		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
 		tp->Rpl[i].FrameSize = 0;
 		tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize);
 
 		/* Alloc skb and point adapter to data area */
 		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);
+			tp->Rpl[i].DMABuff = 0;
 
 		/* skb == NULL ? then use local buffer */
 		if(tp->Rpl[i].Skb == NULL)
 		{
 			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;
-			tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+			tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);
 			tp->Rpl[i].MData = tp->LocalRxBuffers[i];
 		}
 		else	/* SKB != NULL */
@@ -422,17 +441,19 @@
 			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
 
 			/* data unreachable for DMA ? then use local buffer */
-			if(tp->dmalimit && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > tp->dmalimit)
+			dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+			if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
 			{
 				tp->Rpl[i].SkbStat = SKB_DATA_COPY;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+				tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);
 				tp->Rpl[i].MData = tp->LocalRxBuffers[i];
 			}
 			else	/* DMA directly in skb->data */
 			{
 				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));
+				tp->Rpl[i].FragList[0].DataAddr = htonl(dmabuf);
 				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;
+				tp->Rpl[i].DMABuff = dmabuf;
 			}
 		}
 
@@ -506,7 +527,7 @@
 	tp->ocpl.TXBufMin	 = TX_BUF_MIN;
 	tp->ocpl.TXBufMax	 = TX_BUF_MAX;
 
-	Addr = htonl(virt_to_bus(tp->ProductID));
+	Addr = htonl(((char *)tp->ProductID - (char *)tp) + tp->dmabuffer);
 
 	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);
 	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);
@@ -610,10 +631,11 @@
 {
 	TPL *tpl;
 	short length;
-	unsigned char *buf, *newbuf;
+	unsigned char *buf;
 	struct sk_buff *skb;
 	int i;
-    
+	dma_addr_t dmabuf, newbuf;
+   
 	for(;;)
 	{
 		/* Try to get a free TPL from the chain.
@@ -634,26 +656,30 @@
 			return;
 
 		tp->QueueSkb++;
+		dmabuf = 0;
+
 		/* Is buffer reachable for Busmaster-DMA? */
-		if(tp->dmalimit && virt_to_bus((void*)(((long) skb->data) + skb->len)) > tp->dmalimit)
+
+		length	= skb->len;
+		dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE);
+		if(tp->dmalimit && (dmabuf + length > tp->dmalimit))
 		{
 			/* Copy frame to local buffer */
+			pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE);
+			dmabuf  = 0;
 			i 	= tp->TplFree->TPLIndex;
-			length 	= skb->len;
 			buf 	= tp->LocalTxBuffers[i];
 			memcpy(buf, skb->data, length);
-			newbuf 	= buf;
+			newbuf 	= ((char *)buf - (char *)tp) + tp->dmabuffer;
 		}
 		else
 		{
 			/* Send direct from skb->data */
-			length = skb->len;
-			newbuf = skb->data;
+			newbuf	= dmabuf;
+			buf	= skb->data;
 		}
-
 		/* Source address in packet? */
-		tms380tr_chk_src_addr(newbuf, dev->dev_addr);
-
+		tms380tr_chk_src_addr(buf, dev->dev_addr);
 		tp->LastSendTime	= jiffies;
 		tpl 			= tp->TplFree;	/* Get the "free" TPL */
 		tpl->BusyFlag 		= 1;		/* Mark TPL as busy */
@@ -661,12 +687,13 @@
     
 		/* Save the skb for delayed return of skb to system */
 		tpl->Skb = skb;
+		tpl->DMABuff = dmabuf;
 		tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length);
-		tpl->FragList[0].DataAddr  = htonl(virt_to_bus(newbuf));
+		tpl->FragList[0].DataAddr  = htonl(newbuf);
 
 		/* Write the data length in the transmit list. */
 		tpl->FrameSize 	= cpu_to_be16((unsigned short)length);
-		tpl->MData 	= newbuf;
+		tpl->MData 	= buf;
 
 		/* Transmit the frame and set the status values. */
 		tms380tr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME
@@ -1155,9 +1182,10 @@
 	}
 	
 	SIFWRITEW(0xFF00, SIFCMD);
+#if 0
 	if(dev->dma > 0) /* what the? */
 		SIFWRITEB(0xff, POSREG);
-
+#endif
 	tms380tr_cancel_tx_queue(tp);
 
 	return (0);
@@ -1331,6 +1359,7 @@
 		}
 	} while(count == 0);
 
+	printk(KERN_INFO "%s: Adapter Download Failed\n", dev->name);
 	return (-1);
 }
 
@@ -1381,6 +1410,7 @@
 
 	Status = SIFREADW(SIFSTS);
 	
+	printk(KERN_INFO "%s: Hardware error\n", dev->name);
 	/* Hardware error occurred! */
 	Status &= 0x001f;
 	if (Status & 0x0010)
@@ -1412,9 +1442,16 @@
 	int i, loop_cnt, retry_cnt;
 
 	/* Normalize: byte order low/high, word order high/low! (only IPB!) */
-	tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb));
-	tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb));
+	tp->ipb.SCB_Addr = SWAPW(((char *)&tp->scb - (char *)tp) + tp->dmabuffer);
+	tp->ipb.SSB_Addr = SWAPW(((char *)&tp->ssb - (char *)tp) + tp->dmabuffer);
 
+	if(tms380tr_debug > 3)
+	{
+		printk(KERN_INFO "%s: buffer (real): %lx\n", dev->name, (long) &tp->scb);
+		printk(KERN_INFO "%s: buffer (virt): %lx\n", dev->name, (long) ((char *)&tp->scb - (char *)tp) + tp->dmabuffer);
+		printk(KERN_INFO "%s: buffer (DMA) : %lx\n", dev->name, (long) tp->dmabuffer);
+		printk(KERN_INFO "%s: buffer (tp)  : %lx\n", dev->name, (long) tp);
+	}
 	/* Maximum: three initialization retries */
 	retry_cnt = INIT_MAX_RETRIES;
 
@@ -1454,8 +1491,11 @@
 			i = 0;
 			do {	/* Test if contents of SCB is valid */
 				if(SCB_Test[i] != *(cb_ptr + i))
+				{
+					printk(KERN_INFO "%s: DMA failed\n", dev->name);
 					/* DMA data error: wrong data in SCB */
 					return (-1);
+				}
 				i++;
 			} while(i < 6);
 
@@ -1477,6 +1517,7 @@
 				Status = SIFREADW(SIFSTS);
 				Status &= STS_ERROR_MASK;
 				/* ShowInitialisationErrorCode(Status); */
+				printk(KERN_INFO "%s: Status error: %d\n", dev->name, Status);
 				return (-1); /* Unrecoverable error */
 			}
 			else
@@ -1491,6 +1532,7 @@
 		}
 	} while(retry_cnt > 0);
 
+	printk(KERN_INFO "%s: Retry exceeded\n", dev->name);
 	return (-1);
 }
 
@@ -1520,7 +1562,7 @@
 			/* Execute OPEN command	*/
 			tp->CMDqueue ^= OC_OPEN;
 
-			Addr = htonl(virt_to_bus(&tp->ocpl));
+			Addr = htonl(((char *)&tp->ocpl - (char *)tp) + tp->dmabuffer);
 			tp->scb.Parm[0] = LOWORD(Addr);
 			tp->scb.Parm[1] = HIWORD(Addr);
 			tp->scb.CMD = OPEN;
@@ -1554,7 +1596,7 @@
 			if(tp->CMDqueue & OC_RECEIVE)
 			{
 				tp->CMDqueue ^= OC_RECEIVE;
-				Addr = htonl(virt_to_bus(tp->RplHead));
+				Addr = htonl(((char *)tp->RplHead - (char *)tp) + tp->dmabuffer);
 				tp->scb.Parm[0] = LOWORD(Addr);
 				tp->scb.Parm[1] = HIWORD(Addr);
 				tp->scb.CMD = RECEIVE;
@@ -1595,7 +1637,7 @@
 
 						tp->CMDqueue ^= OC_TRANSMIT;
 						tms380tr_cancel_tx_queue(tp);
-						Addr = htonl(virt_to_bus(tp->TplBusy));
+						Addr = htonl(((char *)tp->TplBusy - (char *)tp) + tp->dmabuffer);
 						tp->scb.Parm[0] = LOWORD(Addr);
 						tp->scb.Parm[1] = HIWORD(Addr);
 						tp->scb.CMD = TRANSMIT;
@@ -1634,7 +1676,7 @@
 									if(tp->CMDqueue & OC_READ_ERROR_LOG)
 									{
 										tp->CMDqueue ^= OC_READ_ERROR_LOG;
-										Addr = htonl(virt_to_bus(&tp->errorlogtable));
+										Addr = htonl(((char *)&tp->errorlogtable - (char *)tp) + tp->dmabuffer);
 										tp->scb.Parm[0] = LOWORD(Addr);
 										tp->scb.Parm[1] = HIWORD(Addr);
 										tp->scb.CMD = READ_ERROR_LOG;
@@ -1976,8 +2018,9 @@
 		tpl->BusyFlag = 0;		/* "free" TPL */
 
 		printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
-
-		dev_kfree_skb(tpl->Skb);
+		if (tpl->DMABuff)
+			pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(tpl->Skb);
 	}
 
 	for(;;)
@@ -1986,7 +2029,7 @@
 		if(skb == NULL)
 			break;
 		tp->QueueSkb++;
-		dev_kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 	}
 
 	return;
@@ -2053,7 +2096,9 @@
 		}
 
 		tp->MacStat.tx_packets++;
-		dev_kfree_skb(tpl->Skb);
+		if (tpl->DMABuff)
+			pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(tpl->Skb);
 		tpl->BusyFlag = 0;	/* "free" TPL */
 	}
 
@@ -2075,6 +2120,7 @@
 	unsigned int Length, Length2;
 	RPL *rpl;
 	RPL *SaveHead;
+	dma_addr_t dmabuf;
 
 	/* NOTE: At this point the SSB from RECEIVE STATUS is no longer
 	 * available, because the CLEAR SSB command has already been issued.
@@ -2118,81 +2164,68 @@
 				tp->RplHead = SaveHead;
 				break;	/* Return to tms380tr_interrupt */
 			}
-#if 0  		/* This might happen for multicast or broadcast packets.
-		   The upper layers are expected to handle this, not here */
-
-			/* Drop frames sent by myself */
-			if(tms380tr_chk_frame(dev, rpl->MData))
-			{
-				printk(KERN_INFO "%s: Received my own frame\n",
-					dev->name);
-				if(rpl->Skb != NULL)
-					dev_kfree_skb(rpl->Skb);
-			}
-			else
-#endif
-			{
-			  tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
+			tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
 			  
-			  if(tms380tr_debug > 3)
-			    printk("%s: Packet Length %04X (%d)\n",
-				   dev->name, Length, Length);
+			if(tms380tr_debug > 3)
+				printk("%s: Packet Length %04X (%d)\n",
+					dev->name, Length, Length);
 			  
-				/* Indicate the received frame to system the
-				 * adapter does the Source-Routing padding for 
-				 * us. See: OpenOptions in tms380tr_init_opb()
-				 */
-				skb = rpl->Skb;
-				if(rpl->SkbStat == SKB_UNAVAILABLE)
+			/* Indicate the received frame to system the
+			 * adapter does the Source-Routing padding for 
+			 * us. See: OpenOptions in tms380tr_init_opb()
+			 */
+			skb = rpl->Skb;
+			if(rpl->SkbStat == SKB_UNAVAILABLE)
+			{
+				/* Try again to allocate skb */
+				skb = dev_alloc_skb(tp->MaxPacketSize);
+				if(skb == NULL)
 				{
-					/* Try again to allocate skb */
-					skb = dev_alloc_skb(tp->MaxPacketSize);
-					if(skb == NULL)
-					{
-						/* Update Stats ?? */
-					}
-					else
-					{
-						skb->dev	= dev;
-						skb_put(skb, tp->MaxPacketSize);
-						rpl->SkbStat 	= SKB_DATA_COPY;
-						ReceiveDataPtr 	= rpl->MData;
-					}
+					/* Update Stats ?? */
 				}
-
-				if(rpl->SkbStat == SKB_DATA_COPY
-					|| rpl->SkbStat == SKB_DMA_DIRECT)
+				else
 				{
-					if(rpl->SkbStat == SKB_DATA_COPY)
-						memmove(skb->data, ReceiveDataPtr, Length);
-
-					/* Deliver frame to system */
-					rpl->Skb = NULL;
-					skb_trim(skb,Length);
-					skb->protocol = tr_type_trans(skb,dev);
-					netif_rx(skb);
+					skb->dev	= dev;
+					skb_put(skb, tp->MaxPacketSize);
+					rpl->SkbStat 	= SKB_DATA_COPY;
+					ReceiveDataPtr 	= rpl->MData;
 				}
 			}
+
+			if(rpl->SkbStat == SKB_DATA_COPY
+				|| rpl->SkbStat == SKB_DMA_DIRECT)
+			{
+				if(rpl->SkbStat == SKB_DATA_COPY)
+					memmove(skb->data, ReceiveDataPtr, Length);
+
+				/* Deliver frame to system */
+				rpl->Skb = NULL;
+				skb_trim(skb,Length);
+				skb->protocol = tr_type_trans(skb,dev);
+				netif_rx(skb);
+			}
 		}
 		else	/* Invalid frame */
 		{
 			if(rpl->Skb != NULL)
-				dev_kfree_skb(rpl->Skb);
+				dev_kfree_skb_irq(rpl->Skb);
 
 			/* Skip list. */
 			if(rpl->Status & RX_START_FRAME)
 				/* Frame start bit is set -> overflow. */
 				tp->MacStat.rx_errors++;
 		}
+		if (rpl->DMABuff)
+			pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE);
+		rpl->DMABuff = 0;
 
 		/* Allocate new skb for rpl */
 		rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);
-
 		/* skb == NULL ? then use local buffer */
 		if(rpl->Skb == NULL)
 		{
 			rpl->SkbStat = SKB_UNAVAILABLE;
-			rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+			rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer);
 			rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
 		}
 		else	/* skb != NULL */
@@ -2201,18 +2234,20 @@
 			skb_put(rpl->Skb, tp->MaxPacketSize);
 
 			/* Data unreachable for DMA ? then use local buffer */
-			if(tp->dmalimit && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize > tp->dmalimit)
+			dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+			if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
 			{
 				rpl->SkbStat = SKB_DATA_COPY;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+				rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer);
 				rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
 			}
 			else
 			{
 				/* DMA directly in skb->data */
 				rpl->SkbStat = SKB_DMA_DIRECT;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));
+				rpl->FragList[0].DataAddr = htonl(dmabuf);
 				rpl->MData = rpl->Skb->data;
+				rpl->DMABuff = dmabuf;
 			}
 		}
 
@@ -2267,29 +2302,6 @@
 	return;
 }
 
-#if 0
-/*
- * Check if it is a frame of myself. Compare source address with my current
- * address in reverse direction, and mask out the TR_RII.
- */
-static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr)
-{
-	int i;
-
-	for(i = 5; i > 0; i--)
-	{
-		if(Addr[8 + i] != dev->dev_addr[i])
-			return (0);
-	}
-
-	/* Mask out RIF bit. */
-	if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))
-		return (0);
-
-	return (1);  /* It is my frame. */
-}
-#endif
-
 static int tms380tr_set_mac_address(struct net_device *dev, void *addr)
 {
 	struct net_local *tp = (struct net_local *)dev->priv;
@@ -2322,18 +2334,46 @@
 }
 #endif
 
-int tmsdev_init(struct net_device *dev)
+void tmsdev_term(struct net_device *dev)
+{
+	struct net_local *tp;
+
+	tp = (struct net_local *) dev->priv;
+	pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
+		PCI_DMA_BIDIRECTIONAL);
+	kfree(dev->priv);
+}
+
+int tmsdev_init(struct net_device *dev, unsigned long dmalimit, 
+		struct pci_dev *pdev)
 {
 	if (dev->priv == NULL)
 	{
 		struct net_local *tms_local;
+		dma_addr_t buffer;
 		
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);
 		if (dev->priv == NULL)
+		{
+                        printk("%s: Out of memory for DMA\n",
+                                dev->name);
 			return -ENOMEM;
+		}
 		memset(dev->priv, 0, sizeof(struct net_local));
 		tms_local = (struct net_local *)dev->priv;
 		init_waitqueue_head(&tms_local->wait_for_tok_int);
+		tms_local->dmalimit = dmalimit;
+		tms_local->pdev = pdev;
+                buffer = pci_map_single(pdev, (void *)tms_local,
+                        sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL);
+                if (buffer + sizeof(struct net_local) > dmalimit)
+                {
+			printk("%s: Memory not accessible for DMA\n",
+				dev->name);
+			tmsdev_term(dev);
+			return -ENOMEM;
+		}
+		tms_local->dmabuffer = buffer;
 	}
 	
 	/* These can be overridden by the card driver if needed */
@@ -2357,6 +2397,7 @@
 EXPORT_SYMBOL(tms380tr_close);
 EXPORT_SYMBOL(tms380tr_interrupt);
 EXPORT_SYMBOL(tmsdev_init);
+EXPORT_SYMBOL(tmsdev_term);
 EXPORT_SYMBOL(tms380tr_wait);
 
 struct module *TMS380_module = NULL;
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/tms380tr.h linux/drivers/net/tokenring/tms380tr.h
--- linux-2.4.2-pre4/drivers/net/tokenring/tms380tr.h	Wed Jan 26 13:16:05 2000
+++ linux/drivers/net/tokenring/tms380tr.h	Mon Dec  3 22:29:16 2001
@@ -15,7 +15,9 @@
 int tms380tr_open(struct net_device *dev);
 int tms380tr_close(struct net_device *dev);
 void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-int tmsdev_init(struct net_device *dev);
+int tmsdev_init(struct net_device *dev, unsigned long dmalimit,
+		struct pci_dev *pdev);
+void tmsdev_term(struct net_device *dev);
 void tms380tr_wait(unsigned long time);
 
 #define TMS380TR_MAX_ADAPTERS 7
@@ -360,19 +362,19 @@
 					 */
 
 	/* Interrupt vectors the adapter places on attached system bus. */
-	unsigned char CMD_Status_IV;	/* Interrupt vector: command status. */
-	unsigned char TX_IV;		/* Interrupt vector: transmit. */
-	unsigned char RX_IV;		/* Interrupt vector: receive. */
-	unsigned char Ring_Status_IV;	/* Interrupt vector: ring status. */
-	unsigned char SCB_Clear_IV;	/* Interrupt vector: SCB clear. */
-	unsigned char Adapter_CHK_IV;	/* Interrupt vector: adapter check. */
-
-	unsigned short RX_Burst_Size;	/* Max. number of transfer cycles. */
-	unsigned short TX_Burst_Size;	/* During DMA burst; even value! */
-	unsigned short DMA_Abort_Thrhld;/* Number of DMA retries. */
+	u_int8_t  CMD_Status_IV;    /* Interrupt vector: command status. */
+	u_int8_t  TX_IV;	    /* Interrupt vector: transmit. */
+	u_int8_t  RX_IV;	    /* Interrupt vector: receive. */
+	u_int8_t  Ring_Status_IV;   /* Interrupt vector: ring status. */
+	u_int8_t  SCB_Clear_IV;	    /* Interrupt vector: SCB clear. */
+	u_int8_t  Adapter_CHK_IV;   /* Interrupt vector: adapter check. */
+
+	u_int16_t RX_Burst_Size;    /* Max. number of transfer cycles. */
+	u_int16_t TX_Burst_Size;    /* During DMA burst; even value! */
+	u_int16_t DMA_Abort_Thrhld; /* Number of DMA retries. */
 
-	unsigned long SCB_Addr;	/* SCB address: even, word aligned, high-low */
-	unsigned long SSB_Addr;	/* SSB address: even, word aligned, high-low */
+	u_int32_t SCB_Addr;   /* SCB address: even, word aligned, high-low */
+	u_int32_t SSB_Addr;   /* SSB address: even, word aligned, high-low */
 } IPB, *IPB_Ptr;
 #pragma pack()
 
@@ -463,35 +465,35 @@
 
 #pragma pack(1)
 typedef struct {
-	unsigned short OPENOptions;
-	unsigned char NodeAddr[6];	/* Adapter node address; use ROM 
-					 * address
-					 */
-	unsigned long GroupAddr;	/* Multicast: high order
-					 * bytes = 0xC000
-					 */
-	unsigned long FunctAddr;	/* High order bytes = 0xC000 */
-	unsigned short RxListSize;	/* RPL size: 0 (=26), 14, 20 or
-					 * 26 bytes read by the adapter.
-					 * (Depending on the number of 
-					 * fragments/list)
-					 */
-	unsigned short TxListSize;	/* TPL size */
-	unsigned short BufSize;		/* Is automatically rounded up to the
-					 * nearest nK boundary.
-					 */
-	unsigned short FullDuplex;
-	unsigned short Reserved;
-	unsigned char TXBufMin;		/* Number of adapter buffers reserved
-					 * for transmission a minimum of 2
-					 * buffers must be allocated.
-					 */
-	unsigned char TXBufMax;		/* Maximum number of adapter buffers
-					 * for transmit; a minimum of 2 buffers
-					 * must be available for receive.
-					 * Default: 6
-					 */
-	unsigned short ProdIDAddr[2];	/* Pointer to product ID. */
+	u_int16_t OPENOptions;
+	u_int8_t  NodeAddr[6];	/* Adapter node address; use ROM 
+				 * address
+				 */
+	u_int32_t GroupAddr;	/* Multicast: high order
+				 * bytes = 0xC000
+				 */
+	u_int32_t FunctAddr;	/* High order bytes = 0xC000 */
+	u_int16_t RxListSize;	/* RPL size: 0 (=26), 14, 20 or
+				 * 26 bytes read by the adapter.
+				 * (Depending on the number of 
+				 * fragments/list)
+				 */
+	u_int16_t TxListSize;	/* TPL size */
+	u_int16_t BufSize;	/* Is automatically rounded up to the
+				 * nearest nK boundary.
+				 */
+	u_int16_t FullDuplex;
+	u_int16_t Reserved;
+	u_int8_t  TXBufMin;	/* Number of adapter buffers reserved
+				 * for transmission a minimum of 2
+				 * buffers must be allocated.
+				 */
+	u_int8_t  TXBufMax;	/* Maximum number of adapter buffers
+				 * for transmit; a minimum of 2 buffers
+				 * must be available for receive.
+				 * Default: 6
+				 */
+	u_int16_t ProdIDAddr[2];/* Pointer to product ID. */
 } OPB, *OPB_Ptr;
 #pragma pack()
 
@@ -502,8 +504,8 @@
  */
 #pragma pack(1)
 typedef struct {
-	unsigned short CMD;	/* Command code */
-	unsigned short Parm[2];	/* Pointer to Command Parameter Block */
+	u_int16_t CMD;		/* Command code */
+	u_int16_t Parm[2];	/* Pointer to Command Parameter Block */
 } SCB;	/* System Command Block (32 bit physical address; big endian)*/
 #pragma pack()
 
@@ -515,8 +517,8 @@
  */
 #pragma pack(1)
 typedef struct {
-	unsigned short STS;	/* Status code */
-	unsigned short Parm[3];	/* Parameter or pointer to Status Parameter
+	u_int16_t STS;		/* Status code */
+	u_int16_t Parm[3];	/* Parameter or pointer to Status Parameter
 				 * Block.
 				 */
 } SSB;	/* System Status Block (big endian - physical address)  */
@@ -539,33 +541,33 @@
 
 #pragma pack(1)
 typedef struct {
-	unsigned char Line_Error;	/* Line error: code violation in
+	u_int8_t  Line_Error;		/* Line error: code violation in
 					 * frame or in a token, or FCS error.
 					 */
-	unsigned char Internal_Error;	/* IBM specific. (Reserved_1) */
-	unsigned char Burst_Error;
-	unsigned char ARI_FCI_Error;	/* ARI/FCI bit zero in AMP or
+	u_int8_t  Internal_Error;	/* IBM specific. (Reserved_1) */
+	u_int8_t  Burst_Error;
+	u_int8_t  ARI_FCI_Error;	/* ARI/FCI bit zero in AMP or
 					 * SMP MAC frame.
 					 */
-	unsigned char AbortDelimeters;	/* IBM specific. (Reserved_2) */
-	unsigned char Reserved_3;
-	unsigned char Lost_Frame_Error;	/* Receive of end of transmitted
+	u_int8_t  AbortDelimeters;	/* IBM specific. (Reserved_2) */
+	u_int8_t  Reserved_3;
+	u_int8_t  Lost_Frame_Error;	/* Receive of end of transmitted
 					 * frame failed.
 					 */
-	unsigned char Rx_Congest_Error;	/* Adapter in repeat mode has not
+	u_int8_t  Rx_Congest_Error;	/* Adapter in repeat mode has not
 					 * enough buffer space to copy incoming
 					 * frame.
 					 */
-	unsigned char Frame_Copied_Error;/* ARI bit not zero in frame
+	u_int8_t  Frame_Copied_Error;	/* ARI bit not zero in frame
 					 * addressed to adapter.
 					 */
-	unsigned char Frequency_Error;	/* IBM specific. (Reserved_4) */
-	unsigned char Token_Error;	/* (active only in monitor station) */
-	unsigned char Reserved_5;
-	unsigned char DMA_Bus_Error;	/* DMA bus errors not exceeding the
+	u_int8_t  Frequency_Error;	/* IBM specific. (Reserved_4) */
+	u_int8_t  Token_Error;		/* (active only in monitor station) */
+	u_int8_t  Reserved_5;
+	u_int8_t  DMA_Bus_Error;	/* DMA bus errors not exceeding the
 					 * abort thresholds.
 					 */
-	unsigned char DMA_Parity_Error;	/* DMA parity errors not exceeding
+	u_int8_t  DMA_Parity_Error;	/* DMA parity errors not exceeding
 					 * the abort thresholds.
 					 */
 } ERRORTAB;	/* Adapter error counters */
@@ -575,16 +577,16 @@
 /*--------------------- Send and Receive definitions -------------------*/
 #pragma pack(1)
 typedef struct {
-	unsigned short DataCount;	/* Value 0, even and odd values are
-					 * permitted; value is unaltered most
-					 * significant bit set: following
-					 * fragments last fragment: most
-					 * significant bit is not evaluated.
-					 * (???)
-					 */
-	unsigned long DataAddr;		/* Pointer to frame data fragment;
-					 * even or odd.
-					 */
+	u_int16_t DataCount;	/* Value 0, even and odd values are
+				 * permitted; value is unaltered most
+				 * significant bit set: following
+				 * fragments last fragment: most
+				 * significant bit is not evaluated.
+				 * (???)
+				 */
+	u_int32_t DataAddr;	/* Pointer to frame data fragment;
+				 * even or odd.
+				 */
 } Fragment;
 #pragma pack()
 
@@ -675,17 +677,17 @@
 typedef struct s_TPL TPL;
 
 struct s_TPL {	/* Transmit Parameter List (align on even word boundaries) */
-	unsigned long NextTPLAddr;	/* Pointer to next TPL in chain; if
+	u_int32_t NextTPLAddr;		/* Pointer to next TPL in chain; if
 					 * pointer is odd: this is the last
 					 * TPL. Pointing to itself can cause
 					 * problems!
 					 */
-	volatile unsigned short Status;	/* Initialized by the adapter:
+	volatile u_int16_t Status;	/* Initialized by the adapter:
 					 * CSTAT_REQUEST important: update least
 					 * significant bit first! Set by the
 					 * adapter: CSTAT_COMPLETE status.
 					 */
-	unsigned short FrameSize;	/* Number of bytes to be transmitted
+	u_int16_t FrameSize;		/* Number of bytes to be transmitted
 					 * as a frame including AC/FC,
 					 * Destination, Source, Routing field
 					 * not including CRC, FS, End Delimiter
@@ -714,6 +716,7 @@
 	struct sk_buff *Skb;
 	unsigned char TPLIndex;
 	volatile unsigned char BusyFlag;/* Flag: TPL busy? */
+	dma_addr_t DMABuff;		/* DMA IO bus address from pci_map */
 };
 
 /* ---------------------Receive Functions-------------------------------*
@@ -1015,18 +1018,18 @@
 #pragma pack(1)
 typedef struct s_RPL RPL;
 struct s_RPL {	/* Receive Parameter List */
-	unsigned long NextRPLAddr;	/* Pointer to next RPL in chain
+	u_int32_t NextRPLAddr;		/* Pointer to next RPL in chain
 					 * (normalized = physical 32 bit
 					 * address) if pointer is odd: this
 					 * is last RPL. Pointing to itself can
 					 * cause problems!
 					 */
-	volatile unsigned short Status;	/* Set by creation of Receive Parameter
+	volatile u_int16_t Status;	/* Set by creation of Receive Parameter
 					 * List RECEIVE_CSTAT_COMPLETE set by
 					 * adapter in lists that start or end
 					 * a frame.
 					 */
-	volatile unsigned short FrameSize; /* Number of bytes received as a
+	volatile u_int16_t FrameSize;	 /* Number of bytes received as a
 					 * frame including AC/FC, Destination,
 					 * Source, Routing field not including 
 					 * CRC, FS (Frame Status), End Delimiter
@@ -1054,6 +1057,7 @@
 	struct sk_buff *Skb;
 	SKB_STAT SkbStat;
 	int RPLIndex;
+	dma_addr_t DMABuff;		/* DMA IO bus address from pci_map */
 };
 
 /* Information that need to be kept for each board. */
@@ -1084,6 +1088,7 @@
 	RPL *RplTail;
 	unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE];
 
+	struct pci_dev *pdev;
 	int DataRate;
 	unsigned char ScbInUse;
 	unsigned short CMDqueue;
@@ -1111,6 +1116,9 @@
 	struct tr_statistics MacStat;	/* MAC statistics structure */
 
 	unsigned long dmalimit; /* the max DMA address (ie, ISA) */
+	dma_addr_t    dmabuffer; /* the DMA bus address corresponding to
+				    priv. Might be different from virt_to_bus()
+				    for architectures with IO MMU (Alpha) */
 
 	struct timer_list timer;
 
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/tmsisa.c linux/drivers/net/tokenring/tmsisa.c
--- linux-2.4.2-pre4/drivers/net/tokenring/tmsisa.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tokenring/tmsisa.c	Mon Dec  3 22:29:16 2001
@@ -0,0 +1,464 @@
+/*
+ *  tmsisa.c: A generic network driver for TMS380-based ISA token ring cards.
+ *
+ *  Based on tmspci written 1999 by Adam Fritzler
+ *  
+ *  Written 2000 by Jochen Friedrich
+ *  Dedicated to my girlfriend Steffi Bopp
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ *  This driver module supports the following cards:
+ *	- SysKonnect TR4/16(+) ISA	(SK-4190)
+ *
+ *  Maintainer(s):
+ *    AF        Adam Fritzler           mid@auk.cx
+ *    JF	Jochen Friedrich	jochen@scram.de
+ *
+ *  TODO:
+ *	1. Add support for Proteon TR ISA adapters (1392, 1392+)
+ */
+static const char *version = "tmsisa.c: v1.00 14/01/2001 by Jochen Friedrich\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pci.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include "tms380tr.h"
+
+#define TMS_ISA_IO_EXTENT 32
+
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int portlist[] __initdata = {
+	0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,// SK
+	0
+};
+
+/* A zero-terminated list of IRQs to be probed. 
+ * Used again after initial probe for sktr_chipset_init, called from sktr_open.
+ */
+static unsigned short irqlist[] = {
+	3, 5, 9, 10, 11, 12, 15,
+	0
+};
+
+/* A zero-terminated list of DMAs to be probed. */
+static int dmalist[] __initdata = {
+	5, 6, 7,
+	0
+};
+
+static char *isa_cardname = "SK NET TR 4/16 ISA\0";
+
+int tms_isa_probe(struct net_device *dev);
+static int tms_isa_open(struct net_device *dev);
+static int tms_isa_close(struct net_device *dev);
+static void tms_isa_read_eeprom(struct net_device *dev);
+static unsigned short tms_isa_setnselout_pins(struct net_device *dev);
+
+static unsigned short tms_isa_sifreadb(struct net_device *dev, unsigned short reg)
+{
+	return inb(dev->base_addr + reg);
+}
+
+static unsigned short tms_isa_sifreadw(struct net_device *dev, unsigned short reg)
+{
+	return inw(dev->base_addr + reg);
+}
+
+static void tms_isa_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg)
+{
+	outb(val, dev->base_addr + reg);
+}
+
+static void tms_isa_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg)
+{
+	outw(val, dev->base_addr + reg);
+}
+
+struct tms_isa_card {
+	struct net_device *dev;
+	struct tms_isa_card *next;
+};
+
+static struct tms_isa_card *tms_isa_card_list = NULL;
+
+static int __init tms_isa_probe1(int ioaddr)
+{
+	unsigned char old, chk1, chk2;
+
+	old = inb(ioaddr + SIFADR);	/* Get the old SIFADR value */
+
+	chk1 = 0;	/* Begin with check value 0 */
+	do {
+		/* Write new SIFADR value */
+		outb(chk1, ioaddr + SIFADR);
+
+		/* Read, invert and write */
+		chk2 = inb(ioaddr + SIFADD);
+		chk2 ^= 0x0FE;
+		outb(chk2, ioaddr + SIFADR);
+
+		/* Read, invert and compare */
+		chk2 = inb(ioaddr + SIFADD);
+		chk2 ^= 0x0FE;
+
+		if(chk1 != chk2)
+			return (-1);	/* No adapter */
+
+		chk1 -= 2;
+	} while(chk1 != 0);	/* Repeat 128 times (all byte values) */
+
+    	/* Restore the SIFADR value */
+	outb(old, ioaddr + SIFADR);
+
+	return (0);
+}
+
+int __init tms_isa_probe(struct net_device *dev)
+{
+        static int versionprinted = 0;
+	struct net_local *tp;
+	int j;
+	struct tms_isa_card *card;
+
+	if(check_region(dev->base_addr, TMS_ISA_IO_EXTENT))
+		return -1;
+
+	if(tms_isa_probe1(dev->base_addr))
+		return -1;
+   
+	if (versionprinted++ == 0)
+		printk("%s", version);
+ 
+	/* At this point we have found a valid card. */
+    
+	if (!request_region(dev->base_addr, TMS_ISA_IO_EXTENT, isa_cardname))
+		return -1;
+
+	if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL))
+       	{
+		release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+		return -1;
+	}
+
+	dev->base_addr &= ~3; 
+		
+	tms_isa_read_eeprom(dev);
+
+	printk("%s:    Ring Station Address: ", dev->name);
+	printk("%2.2x", dev->dev_addr[0]);
+	for (j = 1; j < 6; j++)
+		printk(":%2.2x", dev->dev_addr[j]);
+	printk("\n");
+		
+	tp = (struct net_local *)dev->priv;
+	tp->setnselout = tms_isa_setnselout_pins;
+		
+	tp->sifreadb = tms_isa_sifreadb;
+	tp->sifreadw = tms_isa_sifreadw;
+	tp->sifwriteb = tms_isa_sifwriteb;
+	tp->sifwritew = tms_isa_sifwritew;
+	
+	memcpy(tp->ProductID, isa_cardname, PROD_ID_SIZE + 1);
+
+	tp->tmspriv = NULL;
+
+	dev->open = tms_isa_open;
+	dev->stop = tms_isa_close;
+
+	if (dev->irq == 0)
+	{
+		for(j = 0; irqlist[j] != 0; j++)
+		{
+			dev->irq = irqlist[j];
+			if (!request_irq(dev->irq, tms380tr_interrupt, 0, 
+				isa_cardname, dev))
+				break;
+                }
+		
+                if(irqlist[j] == 0)
+                {
+                        printk("%s: AutoSelect no IRQ available\n", dev->name);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			tmsdev_term(dev);
+			return -1;
+		}
+	}
+	else
+	{
+		for(j = 0; irqlist[j] != 0; j++)
+			if (irqlist[j] == dev->irq)
+				break;
+		if (irqlist[j] == 0)
+		{
+			printk("%s: Illegal IRQ %d specified\n",
+				dev->name, dev->irq);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			tmsdev_term(dev);
+			return -1;
+		}
+		if (request_irq(dev->irq, tms380tr_interrupt, 0, 
+			isa_cardname, dev))
+		{
+                        printk("%s: Selected IRQ %d not available\n", 
+				dev->name, dev->irq);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			tmsdev_term(dev);
+			return -1;
+		}
+	}
+
+	if (dev->dma == 0)
+	{
+		for(j = 0; dmalist[j] != 0; j++)
+		{
+			dev->dma = dmalist[j];
+                        if (!request_dma(dev->dma, isa_cardname))
+				break;
+		}
+
+		if(dmalist[j] == 0)
+		{
+			printk("%s: AutoSelect no DMA available\n", dev->name);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			free_irq(dev->irq, dev);
+			tmsdev_term(dev);
+			return -1;
+		}
+	}
+	else
+	{
+		for(j = 0; dmalist[j] != 0; j++)
+			if (dmalist[j] == dev->dma)
+				break;
+		if (dmalist[j] == 0)
+		{
+                        printk("%s: Illegal DMA %d specified\n", 
+				dev->name, dev->dma);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			free_irq(dev->irq, dev);
+			tmsdev_term(dev);
+			return -1;
+		}
+		if (request_dma(dev->dma, isa_cardname))
+		{
+                        printk("%s: Selected DMA %d not available\n", 
+				dev->name, dev->dma);
+			release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+			free_irq(dev->irq, dev);
+			tmsdev_term(dev);
+			return -1;
+		}
+	}
+
+	printk("%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
+	       dev->name, dev->base_addr, dev->irq, dev->dma);
+		
+	if (register_trdev(dev) == 0) 
+	{
+		/* Enlist in the card list */
+		card = kmalloc(sizeof(struct tms_isa_card), GFP_KERNEL);
+		card->next = tms_isa_card_list;
+		tms_isa_card_list = card;
+		card->dev = dev;
+	} 
+	else 
+	{
+		printk("%s: register_trdev() returned non-zero.\n", dev->name);
+		release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+		free_irq(dev->irq, dev);
+		free_dma(dev->dma);
+		tmsdev_term(dev);
+		return -1;
+	}
+	
+	return 0;
+}
+
+/*
+ * Reads MAC address from adapter RAM, which should've read it from
+ * the onboard ROM.  
+ *
+ * Calling this on a board that does not support it can be a very
+ * dangerous thing.  The Madge board, for instance, will lock your
+ * machine hard when this is called.  Luckily, its supported in a
+ * seperate driver.  --ASF
+ */
+static void tms_isa_read_eeprom(struct net_device *dev)
+{
+	int i;
+	
+	/* Address: 0000:0000 */
+	tms_isa_sifwritew(dev, 0, SIFADX);
+	tms_isa_sifwritew(dev, 0, SIFADR);	
+	
+	/* Read six byte MAC address data */
+	dev->addr_len = 6;
+	for(i = 0; i < 6; i++)
+		dev->dev_addr[i] = tms_isa_sifreadw(dev, SIFINC) >> 8;
+}
+
+unsigned short tms_isa_setnselout_pins(struct net_device *dev)
+{
+	return 0;
+}
+
+static int tms_isa_open(struct net_device *dev)
+{  
+	struct net_local *tp = (struct net_local *)dev->priv;
+	unsigned short val = 0;
+	unsigned short oldval;
+	int i;
+
+	val = 0;
+	for(i = 0; irqlist[i] != 0; i++)
+	{
+		if(irqlist[i] == dev->irq)
+			break;
+	}
+
+	val |= CYCLE_TIME << 2;
+	val |= i << 4;
+	i = dev->dma - 5;
+	val |= i;
+	if(tp->DataRate == SPEED_4)
+		val |= LINE_SPEED_BIT;
+	else
+		val &= ~LINE_SPEED_BIT;
+	oldval = tms_isa_sifreadb(dev, POSREG);
+	/* Leave cycle bits alone */
+	oldval |= 0xf3;
+	val &= oldval;
+	tms_isa_sifwriteb(dev, val, POSREG);
+
+	tms380tr_open(dev);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int tms_isa_close(struct net_device *dev)
+{
+	tms380tr_close(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef MODULE
+
+#define ISATR_MAX_ADAPTERS 3
+
+static int io[ISATR_MAX_ADAPTERS];
+static int irq[ISATR_MAX_ADAPTERS];
+static int dma[ISATR_MAX_ADAPTERS];
+
+MODULE_PARM(io, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
+
+int init_module(void)
+{
+	int i, num;
+	struct net_device *dev;
+
+	num = 0;
+	if (io[0]) 
+	{ /* Only probe addresses from command line */
+		for (i = 0; i < ISATR_MAX_ADAPTERS; i++)
+	       	{
+			if (io[i] == 0)
+				continue;
+
+			dev = init_trdev(NULL, 0);
+			if (!dev)
+				return (-ENOMEM);
+		
+			dev->base_addr = io[i];
+			dev->irq       = irq[i];
+			dev->dma       = dma[i];
+
+			if (tms_isa_probe(dev))
+			{
+				unregister_netdev(dev);
+				kfree(dev);
+			}
+			else
+				num++;
+		}
+	}
+       	else
+       	{
+		for(i = 0; portlist[i]; i++)
+		{
+			if (num >= ISATR_MAX_ADAPTERS)
+				continue;
+
+			dev = init_trdev(NULL, 0);
+			if (!dev)
+				return (-ENOMEM);
+		
+			dev->base_addr = portlist[i];
+			dev->irq       = irq[num];
+			dev->dma       = dma[num];
+
+			if (tms_isa_probe(dev))
+			{
+				unregister_netdev(dev);
+				kfree(dev);
+			}
+			else
+				num++;
+		}
+	}
+	printk(KERN_NOTICE "tmsisa.c: %d cards found.\n", num);
+	/* Probe for cards. */
+	if (num == 0) {
+		printk(KERN_NOTICE "tmsisa.c: No cards found.\n");
+	}
+	return (0);
+}
+
+void cleanup_module(void)
+{
+	struct net_device *dev;
+	struct tms_isa_card *this_card;
+
+	while (tms_isa_card_list) {
+		dev = tms_isa_card_list->dev;
+		
+		unregister_netdev(dev);
+		release_region(dev->base_addr, TMS_ISA_IO_EXTENT);
+		free_irq(dev->irq, dev);
+		free_dma(dev->dma);
+		tmsdev_term(dev);
+		kfree(dev);
+		this_card = tms_isa_card_list;
+		tms_isa_card_list = this_card->next;
+		kfree(this_card);
+	}
+}
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmsisa.c"
+ *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmsisa.c"
+ *  c-set-style "K&R"
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -urN linux-2.4.2-pre4/drivers/net/tokenring/tmspci.c linux/drivers/net/tokenring/tmspci.c
--- linux-2.4.2-pre4/drivers/net/tokenring/tmspci.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/net/tokenring/tmspci.c	Mon Dec  3 22:29:16 2001
@@ -142,14 +142,14 @@
 		printk(":%2.2x", dev->dev_addr[i]);
 	printk("\n");
 		
-	ret = tmsdev_init(dev);
+	ret = tmsdev_init(dev,0, pdev);
+	/* XXX: should be the max PCI32 DMA max */
 	if (ret) {
 		printk("%s: unable to get memory for dev->priv.\n", dev->name);
 		goto err_out_irq;
 	}
 
 	tp = dev->priv;
-	tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */
 	tp->setnselout = tms_pci_setnselout_pins;
 		
 	tp->sifreadb = tms_pci_sifreadb;
@@ -172,7 +172,7 @@
 	return 0;
 
 err_out_tmsdev:
-	kfree(dev->priv);
+	tmsdev_term(dev);
 err_out_irq:
 	free_irq(pdev->irq, dev);
 err_out_region:
@@ -228,7 +228,7 @@
 	unregister_netdev(dev);
 	release_region(dev->base_addr, TMS_PCI_IO_EXTENT);
 	free_irq(dev->irq, dev);
-	kfree(dev->priv);
+	tmsdev_term(dev);
 	kfree(dev);
 	pci_set_drvdata(pdev, NULL);
 }
diff -urN linux-2.4.2-pre4/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c
--- linux-2.4.2-pre4/drivers/parport/parport_sunbpp.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/parport/parport_sunbpp.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.10 2000/03/27 01:47:56 anton Exp $
+/* $Id: parport_sunbpp.c,v 1.11 2001/02/13 01:16:58 davem Exp $
  * Parallel-port routines for Sun architecture
  * 
  * Author: Derrick J. Brashear <shadow@dementia.org>
diff -urN linux-2.4.2-pre4/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux-2.4.2-pre4/drivers/pci/pci.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pci/pci.c	Mon Dec  3 22:29:16 2001
@@ -20,7 +20,6 @@
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
-#include <linux/slab.h>
 #include <linux/kmod.h>		/* for hotplug_path */
 
 #include <asm/page.h>
diff -urN linux-2.4.2-pre4/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in
--- linux-2.4.2-pre4/drivers/pcmcia/Config.in	Thu Nov 16 16:38:16 2000
+++ linux/drivers/pcmcia/Config.in	Mon Dec  3 22:29:16 2001
@@ -19,6 +19,9 @@
    fi
    bool '  i82365 compatible bridge support' CONFIG_I82365
    bool '  Databook TCIC host bridge support' CONFIG_TCIC
+   if [ "$CONFIG_HD64465" = "y" ]; then
+      dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
+   fi
 fi
 
 endmenu
diff -urN linux-2.4.2-pre4/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile
--- linux-2.4.2-pre4/drivers/pcmcia/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/pcmcia/Makefile	Mon Dec  3 22:29:16 2001
@@ -32,6 +32,9 @@
   ifeq ($(CONFIG_TCIC),y)
     obj-y += tcic.o
   endif
+  ifeq ($(CONFIG_HD64465_PCMCIA),y)
+    obj-y += hd64465_ss.o
+  endif
 else
   ifeq ($(CONFIG_PCMCIA),m)
     obj-m   := pcmcia_core.o ds.o
@@ -40,6 +43,9 @@
     endif
     ifeq ($(CONFIG_TCIC),y)
       obj-m += tcic.o
+    endif
+    ifeq ($(CONFIG_HD64465_PCMCIA),m)
+      obj-m += hd64465_ss.o
     endif
      ifeq ($(CONFIG_CARDBUS),y)
 	obj-m += yenta_socket.o cb_enabler.o
diff -urN linux-2.4.2-pre4/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- linux-2.4.2-pre4/drivers/pcmcia/bulkmem.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/bulkmem.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- linux-2.4.2-pre4/drivers/pcmcia/cardbus.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/cardbus.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c
--- linux-2.4.2-pre4/drivers/pcmcia/cb_enabler.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/cb_enabler.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/cirrus.h linux/drivers/pcmcia/cirrus.h
--- linux-2.4.2-pre4/drivers/pcmcia/cirrus.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/cirrus.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- linux-2.4.2-pre4/drivers/pcmcia/cistpl.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/cistpl.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-2.4.2-pre4/drivers/pcmcia/cs.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/cs.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-2.4.2-pre4/drivers/pcmcia/ds.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/ds.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c
--- linux-2.4.2-pre4/drivers/pcmcia/hd64465_ss.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/hd64465_ss.c	Mon Dec  3 22:29:16 2001
@@ -0,0 +1,1088 @@
+/*
+ * $Id$
+ *
+ * Device driver for the PCMCIA controller module of the
+ * Hitachi HD64465 handheld companion chip.
+ *
+ * Note that the HD64465 provides a very thin PCMCIA host bridge
+ * layer, requiring a lot of the work of supporting cards to be
+ * performed by the processor.  For example: mapping of card
+ * interrupts to processor IRQs is done by IRQ demuxing software;
+ * IO and memory mappings are fixed; setting voltages according
+ * to card Voltage Select pins etc is done in software.
+ *
+ * Note also that this driver uses only the simple, fixed,
+ * 16MB, 16-bit wide mappings to PCMCIA spaces defined by the
+ * HD64465.  Larger mappings, smaller mappings, or mappings of
+ * different width to the same socket, are all possible only by
+ * involving the SH7750's MMU, which is considered unnecessary here.
+ * The downside is that it may be possible for some drivers to
+ * break because they need or expect 8-bit mappings.
+ *
+ * This driver currently supports only the following configuration:
+ * SH7750 CPU, HD64465, TPS2206 voltage control chip.
+ *
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <asm/errno.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/hd64465.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+#define MODNAME "hd64465_ss"
+
+/* #define HD64465_DEBUG 1 */
+
+#ifndef HD64465_DEBUG
+#define HD64465_DEBUG 0
+#endif
+
+#if HD64465_DEBUG
+#define DPRINTK(args...)	printk(MODNAME ": " args)
+#else
+#define DPRINTK(args...)
+#endif
+
+extern int hd64465_io_debug;
+
+
+/*============================================================*/
+
+#define HS_IO_MAP_SIZE 	(64*1024)
+
+typedef struct hs_socket_t
+{
+    u_int   	    	irq;
+    u_long  	    	mem_base;
+    u_long  	    	mem_length;
+    void	    	(*handler)(void *info, u_int events);
+    void    	    	*handler_info;
+    u_int   	    	pending_events;
+    u_int   	    	ctrl_base;
+    socket_state_t  	state;
+    pccard_io_map     	io_maps[MAX_IO_WIN];
+    pccard_mem_map  	mem_maps[MAX_WIN];
+    struct vm_struct	*io_vma;    /* allocated kernel vm for mapping IO space */
+} hs_socket_t;
+
+#define HS_MAX_SOCKETS 2
+static hs_socket_t hs_sockets[HS_MAX_SOCKETS];
+static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+/* Calculate socket number from ptr into hs_sockets[] */
+#define hs_sockno(sp) 	(sp - hs_sockets)
+
+static socket_cap_t hs_socket_cap =
+{
+    SS_CAP_PCCARD   	    /* support 16 bit cards */
+    |SS_CAP_STATIC_MAP      /* mappings are fixed in host memory */
+    ,
+    0xffde/*0xffff*/, 	    /* IRQs mapped in s/w so can do any, really */
+    HD64465_PCC_WINDOW,     /* 16MB fixed window size */
+    0,	    	    	    /* no PCI support */
+    0,	    	    	    /* no CardBus support */
+    0	    	    	    /* no bus operations needed */
+};
+
+#define hs_in(sp, r)	    inb((sp)->ctrl_base + (r))
+#define hs_out(sp, v, r)    outb(v, (sp)->ctrl_base + (r))
+
+
+/* translate a boolean value to a bit in a register */
+#define bool_to_regbit(sp, r, bi, bo)	    	\
+    do {    	    	    	    	    	\
+    	unsigned short v = hs_in(sp, r);    	\
+	if (bo)     	    	    	    	\
+	    v |= (bi);	    	    	    	\
+	else	    	    	    	    	\
+	    v &= ~(bi);     	    	    	\
+	hs_out(sp, v, r);   	    	    	\
+    } while(0)
+    
+/* register offsets from HD64465_REG_PCC[01]ISR */
+#define ISR 	0x0
+#define GCR 	0x2
+#define CSCR 	0x4
+#define CSCIER 	0x6
+#define SCR 	0x8
+
+
+/* Mask and values for CSCIER register */
+#define IER_MASK    0x80
+#define IER_ON	    0x3f    	/* interrupts on */
+#define IER_OFF     0x00    	/* interrupts off */
+
+/*============================================================*/
+
+#if HD64465_DEBUG > 10
+
+static void cis_hex_dump(const unsigned char *x, int len)
+{
+    	int i;
+	
+    	for (i=0 ; i<len ; i++)
+	{
+	    if (!(i & 0xf))
+	    	printk("\n%08x", (unsigned)(x + i));
+	    printk(" %02x", *(volatile unsigned short*)x);
+	    x += 2;
+	}
+	printk("\n");
+}
+
+#endif
+/*============================================================*/
+
+/*
+ * This code helps create the illusion that the IREQ line from
+ * the PC card is mapped to one of the CPU's IRQ lines by the
+ * host bridge hardware (which is how every host bridge *except*
+ * the HD64465 works).  In particular, it supports enabling
+ * and disabling the IREQ line by code which knows nothing
+ * about the host bridge (e.g. device drivers, IDE code) using
+ * the request_irq(), free_irq(), probe_irq_on() and probe_irq_off()
+ * functions.  Also, it supports sharing the mapped IRQ with
+ * real hardware IRQs from the -IRL0-3 lines.
+ */
+
+#define HS_NUM_MAPPED_IRQS  16	/* Limitation of the PCMCIA code */
+static struct
+{
+    /* index is mapped irq number */
+    hs_socket_t *sock;
+    hw_irq_controller *old_handler;
+} hs_mapped_irq[HS_NUM_MAPPED_IRQS];
+
+static void hs_socket_enable_ireq(hs_socket_t *sp)
+{
+    	unsigned short cscier;
+	
+    	DPRINTK("hs_socket_enable_ireq(sock=%d)\n", hs_sockno(sp));
+
+    	cscier = hs_in(sp, CSCIER);
+	cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
+    	cscier |= HD64465_PCCCSCIER_PIREQE_LEVEL;
+	hs_out(sp, cscier, CSCIER);
+}
+
+static void hs_socket_disable_ireq(hs_socket_t *sp)
+{
+    	unsigned short cscier;
+	
+    	DPRINTK("hs_socket_disable_ireq(sock=%d)\n", hs_sockno(sp));
+	
+    	cscier = hs_in(sp, CSCIER);
+	cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
+	hs_out(sp, cscier, CSCIER);
+}
+
+static unsigned int hs_startup_irq(unsigned int irq)
+{
+	hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
+	hs_mapped_irq[irq].old_handler->startup(irq);
+	return 0;
+}
+
+static void hs_shutdown_irq(unsigned int irq)
+{
+	hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
+	hs_mapped_irq[irq].old_handler->shutdown(irq);
+}
+
+static void hs_enable_irq(unsigned int irq)
+{
+	hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
+	hs_mapped_irq[irq].old_handler->enable(irq);
+}
+
+static void hs_disable_irq(unsigned int irq)
+{
+	hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
+	hs_mapped_irq[irq].old_handler->disable(irq);
+}
+
+extern struct hw_interrupt_type no_irq_type;
+
+static void hs_mask_and_ack_irq(unsigned int irq)
+{
+	hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
+	/* ack_none() spuriously complains about an unexpected IRQ */
+	if (hs_mapped_irq[irq].old_handler != &no_irq_type)
+	    hs_mapped_irq[irq].old_handler->ack(irq);
+}
+
+static void hs_end_irq(unsigned int irq)
+{
+	hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
+	hs_mapped_irq[irq].old_handler->end(irq);
+}
+
+
+static struct hw_interrupt_type hd64465_ss_irq_type = {
+	typename:	"PCMCIA-IRQ",
+	startup:	hs_startup_irq,
+	shutdown:	hs_shutdown_irq,
+	enable:		hs_enable_irq,
+	disable:	hs_disable_irq,
+	ack:		hs_mask_and_ack_irq,
+	end:		hs_end_irq
+};
+
+/* 
+ * This function should only ever be called with interrupts disabled.
+ */
+static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
+{
+    	DPRINTK("hs_map_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
+	
+	if (irq >= HS_NUM_MAPPED_IRQS)
+	    return;
+
+    	hs_mapped_irq[irq].sock = sp;
+	/* insert ourselves as the irq controller */
+	hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
+	irq_desc[irq].handler = &hd64465_ss_irq_type;
+}
+
+
+/* 
+ * This function should only ever be called with interrupts disabled.
+ */
+static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
+{
+    	DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
+	
+	if (irq >= HS_NUM_MAPPED_IRQS)
+	    return;
+		
+	/* restore the original irq controller */
+	irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
+}
+
+/*============================================================*/
+
+
+/*
+ * Set Vpp and Vcc (in tenths of a Volt).  Does not
+ * support the hi-Z state.
+ *
+ * Note, this assumes the board uses a TPS2206 chip to control
+ * the Vcc and Vpp voltages to the hs_sockets.  If your board
+ * uses the MIC2563 (also supported by the HD64465) then you
+ * will have to modify this function.
+ */
+    	    	    	    	         /* 0V   3.3V  5.5V */
+static const u_char hs_tps2206_avcc[3] = { 0x00, 0x04, 0x08 };
+static const u_char hs_tps2206_bvcc[3] = { 0x00, 0x80, 0x40 };
+
+static int hs_set_voltages(hs_socket_t *sp, int Vcc, int Vpp)
+{
+    	u_int psr;
+	u_int vcci = 0;
+	u_int sock = hs_sockno(sp);
+	
+    	DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp);
+
+    	switch (Vcc)
+	{
+	case 0:  vcci = 0; break;
+	case 33: vcci = 1; break;
+	case 50: vcci = 2; break;
+	default: return 0;
+	}
+
+    	/* Note: Vpp = 120 not supported -- Greg Banks */
+	if (Vpp != 0 && Vpp != Vcc)
+	    return 0;
+	
+	/* The PSR register holds 8 of the 9 bits which control
+	 * the TPS2206 via its serial interface.
+	 */
+	psr = inw(HD64465_REG_PCCPSR);
+	switch (sock)
+	{
+	case 0:
+	    psr &= 0x0f;
+	    psr |= hs_tps2206_avcc[vcci];
+	    psr |= (Vpp == 0 ? 0x00 : 0x02);
+	    break;
+	case 1:
+	    psr &= 0xf0;
+	    psr |= hs_tps2206_bvcc[vcci];
+	    psr |= (Vpp == 0 ? 0x00 : 0x20);
+	    break;
+	};
+	outw(psr, HD64465_REG_PCCPSR);
+	
+	return 1;
+}
+
+
+/*============================================================*/
+
+/*
+ * Drive the RESET line to the card.
+ */
+static void hs_reset_socket(hs_socket_t *sp, int on)
+{
+    	unsigned short v;
+	
+	v = hs_in(sp, GCR);
+	if (on)
+	    v |= HD64465_PCCGCR_PCCR;
+	else
+	    v &= ~HD64465_PCCGCR_PCCR;
+	hs_out(sp, v, GCR);
+}
+
+/*============================================================*/
+
+static int hs_init(unsigned int sock)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	
+    	DPRINTK("hs_init(%d)\n", sock);
+	
+	sp->pending_events = 0;
+	sp->state.Vcc = 0;
+	sp->state.Vpp = 0;
+	hs_set_voltages(sp, 0, 0);
+	
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_suspend(unsigned int sock)
+{
+    	DPRINTK("hs_suspend(%d)\n", sock);
+
+    	/* TODO */
+	
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_register_callback(unsigned int sock,
+    	    void (*handler)(void *, unsigned int), void * info)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	
+    	DPRINTK("hs_register_callback(%d)\n", sock);
+	sp->handler = handler;
+	sp->handler_info = info;
+	if (handler == 0) {
+	    MOD_DEC_USE_COUNT;
+	} else {
+	    MOD_INC_USE_COUNT;
+	}
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+    	DPRINTK("hs_inquire_socket(%d)\n", sock);
+
+	*cap = hs_socket_cap;
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_get_status(unsigned int sock, u_int *value)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+    	unsigned int isr;
+	u_int status = 0;
+	
+	
+	isr = hs_in(sp, ISR);
+
+    	/* Card is seated and powered when *both* CD pins are low */
+	if ((isr & HD64465_PCCISR_PCD_MASK) == 0)
+    	{
+	    status |= SS_DETECT;    /* card present */
+
+	    switch (isr & HD64465_PCCISR_PBVD_MASK)
+	    {
+	    case HD64465_PCCISR_PBVD_BATGOOD:   
+		break;
+	    case HD64465_PCCISR_PBVD_BATWARN:
+		status |= SS_BATWARN;
+		break;
+	    default:
+		status |= SS_BATDEAD;
+		break;
+	    }
+
+	    if (isr & HD64465_PCCISR_PREADY)
+		status |= SS_READY;
+
+	    if (isr & HD64465_PCCISR_PMWP)
+		status |= SS_WRPROT;
+		
+	    /* Voltage Select pins interpreted as per Table 4-5 of the std.
+	     * Assuming we have the TPS2206, the socket is a "Low Voltage
+	     * key, 3.3V and 5V available, no X.XV available".
+	     */
+	    switch (isr & (HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1))
+	    {
+	    case HD64465_PCCISR_PVS1:
+	    	printk(KERN_NOTICE MODNAME ": cannot handle X.XV card, ignored\n");
+		status = 0;
+	    	break;
+	    case 0:
+	    case HD64465_PCCISR_PVS2:
+    	    	/* 3.3V */
+    	    	status |= SS_3VCARD;
+	    	break;
+	    case HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1:
+	    	/* 5V */
+	    	break;
+	    }
+		
+	    /* TODO: SS_POWERON */
+	    /* TODO: SS_STSCHG */
+    	}	
+	
+    	DPRINTK("hs_get_status(%d) = %x\n", sock, status);
+	
+	*value = status;
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_get_socket(unsigned int sock, socket_state_t *state)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+
+    	DPRINTK("hs_get_socket(%d)\n", sock);
+	
+	*state = sp->state;
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_set_socket(unsigned int sock, socket_state_t *state)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+    	u_long flags;
+	u_int changed;
+	unsigned short cscier;
+
+    	DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n",
+	    sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq);
+	
+	save_and_cli(flags);	/* Don't want interrupts happening here */
+
+	if (state->Vpp != sp->state.Vpp ||
+	    state->Vcc != sp->state.Vcc) {
+	    if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) {
+	    	restore_flags(flags);
+	    	return -EINVAL;
+	    }
+	}
+
+/*    	hd64465_io_debug = 1; */
+    	/*
+	 * Handle changes in the Card Status Change mask,
+	 * by propagating to the CSCR register
+	 */	
+	changed = sp->state.csc_mask ^ state->csc_mask;
+	cscier = hs_in(sp, CSCIER);
+	    
+	if (changed & SS_DETECT) {
+	    if (state->csc_mask & SS_DETECT)
+		cscier |= HD64465_PCCCSCIER_PCDE;
+	    else
+		cscier &= ~HD64465_PCCCSCIER_PCDE;
+	}
+
+	if (changed & SS_READY) {
+	    if (state->csc_mask & SS_READY)
+		cscier |= HD64465_PCCCSCIER_PRE;
+	    else
+		cscier &= ~HD64465_PCCCSCIER_PRE;
+	}
+
+	if (changed & SS_BATDEAD) {
+	    if (state->csc_mask & SS_BATDEAD)
+		cscier |= HD64465_PCCCSCIER_PBDE;
+	    else
+		cscier &= ~HD64465_PCCCSCIER_PBDE;
+	}
+
+	if (changed & SS_BATWARN) {
+	    if (state->csc_mask & SS_BATWARN)
+		cscier |= HD64465_PCCCSCIER_PBWE;
+	    else
+		cscier &= ~HD64465_PCCCSCIER_PBWE;
+	}
+
+	if (changed & SS_STSCHG) {
+	    if (state->csc_mask & SS_STSCHG)
+		cscier |= HD64465_PCCCSCIER_PSCE;
+	    else
+		cscier &= ~HD64465_PCCCSCIER_PSCE;
+	}
+
+    	hs_out(sp, cscier, CSCIER);
+
+	if (sp->state.io_irq && !state->io_irq)
+	    hs_unmap_irq(sp, sp->state.io_irq);
+	else if (!sp->state.io_irq && state->io_irq)
+	    hs_map_irq(sp, state->io_irq);
+
+
+    	/*
+	 * Handle changes in the flags field,
+	 * by propagating to config registers.
+	 */	
+	changed = sp->state.flags ^ state->flags;
+
+	if (changed & SS_IOCARD) {
+	    DPRINTK("card type: %s\n",
+		    (state->flags & SS_IOCARD ? "i/o" : "memory" ));
+	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCT,
+		state->flags & SS_IOCARD);
+	}
+
+	if (changed & SS_RESET) {
+	    DPRINTK("%s reset card\n",
+		(state->flags & SS_RESET ? "start" : "stop"));
+	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCR,
+		state->flags & SS_RESET);
+	}
+
+	if (changed & SS_OUTPUT_ENA) {
+	    DPRINTK("%sabling card output\n",
+		(state->flags & SS_OUTPUT_ENA ? "en" : "dis"));
+	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PDRV,
+		state->flags & SS_OUTPUT_ENA);
+	}
+
+    	/* TODO: SS_SPKR_ENA */
+	    
+/*    	hd64465_io_debug = 0; */
+	sp->state = *state;
+	    
+	restore_flags(flags);
+
+#if HD64465_DEBUG > 10
+	if (state->flags & SS_OUTPUT_ENA)   
+	    cis_hex_dump((const unsigned char*)sp->mem_base, 0x100);
+#endif
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	int map = io->map;
+
+    	DPRINTK("hs_get_io_map(%d, %d)\n", sock, map);
+	if (map >= MAX_IO_WIN)
+	    return -EINVAL;
+	
+	*io = sp->io_maps[map];
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	int map = io->map;
+	struct pccard_io_map *sio;
+	pgprot_t prot;
+
+    	DPRINTK("hs_set_io_map(sock=%d, map=%d, flags=0x%x, speed=%dns, start=0x%04x, stop=0x%04x)\n",
+	    sock, map, io->flags, io->speed, io->start, io->stop);
+	if (map >= MAX_IO_WIN)
+	    return -EINVAL;
+	sio = &sp->io_maps[map];
+
+    	/* check for null changes */	
+    	if (io->flags == sio->flags &&
+	    io->start == sio->start &&
+	    io->stop == sio->stop)
+	    return 0;
+	
+	if (io->flags & MAP_AUTOSZ)
+	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IODYN);
+	else if (io->flags & MAP_16BIT)
+	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO16);
+	else
+	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO8);
+
+	/* TODO: handle MAP_USE_WAIT */
+	if (io->flags & MAP_USE_WAIT)
+	    printk(KERN_INFO MODNAME ": MAP_USE_WAIT unimplemented\n");
+	/* TODO: handle MAP_PREFETCH */
+	if (io->flags & MAP_PREFETCH)
+	    printk(KERN_INFO MODNAME ": MAP_PREFETCH unimplemented\n");
+	/* TODO: handle MAP_WRPROT */
+	if (io->flags & MAP_WRPROT)
+	    printk(KERN_INFO MODNAME ": MAP_WRPROT unimplemented\n");
+	/* TODO: handle MAP_0WS */
+	if (io->flags & MAP_0WS)
+	    printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n");
+
+	if (io->flags & MAP_ACTIVE) {
+	    unsigned long pstart, psize, paddrbase, vaddrbase;
+	    
+	    paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW));
+	    vaddrbase = (unsigned long)sp->io_vma->addr;
+	    pstart = io->start & PAGE_MASK;
+	    psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart;
+
+    	    /*
+	     * Change PTEs in only that portion of the mapping requested
+	     * by the caller.  This means that most of the time, most of
+	     * the PTEs in the io_vma will be unmapped and only the bottom
+	     * page will be mapped.  But the code allows for weird cards
+	     * that might want IO ports > 4K.
+	     */
+	    DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",
+	    	vaddrbase + pstart, paddrbase + pstart, psize);
+	    remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
+	    
+	    /*
+	     * Change the mapping used by inb() outb() etc
+	     */
+	    hd64465_port_map(
+	    	io->start,
+		io->stop - io->start + 1,
+	    	vaddrbase + io->start);
+	} else {
+	    hd64465_port_unmap(
+	    	sio->start,
+		sio->stop - sio->start + 1);
+	    /* TODO: remap_page_range() to mark pages not present ? */
+	}
+	
+	*sio = *io;
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	int map = mem->map;
+
+    	DPRINTK("hs_get_mem_map(%d, %d)\n", sock, map);
+	if (map >= MAX_WIN)
+	    return -EINVAL;
+	
+	*mem = sp->mem_maps[map];
+	return 0;
+}
+
+/*============================================================*/
+
+static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+    	hs_socket_t *sp = &hs_sockets[sock];
+	struct pccard_mem_map *smem;
+	int map = mem->map;
+	unsigned long paddr, size;
+
+#if 0
+    	DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)\n",
+	    sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start);
+#endif
+
+	if (map >= MAX_WIN)
+	    return -EINVAL;
+	smem = &sp->mem_maps[map];
+	
+	size = mem->sys_stop - mem->sys_start + 1;
+	
+	paddr = sp->mem_base;	    	    /* base of Attribute mapping */
+	if (!(mem->flags & MAP_ATTRIB))
+	    paddr += HD64465_PCC_WINDOW;    /* base of Common mapping */
+	paddr += mem->card_start;
+
+    	/* Because we specified SS_CAP_STATIC_MAP, we are obliged
+	 * at this time to report the system address corresponding
+	 * to the card address requested.  This is how Socket Services
+	 * queries our fixed mapping.  I wish this fact had been
+	 * documented - Greg Banks.
+	 */
+    	mem->sys_start = paddr;
+	mem->sys_stop = paddr + size - 1;
+	
+	*smem = *mem;
+	
+    	return 0;
+}
+
+/* TODO: do we need to use the MMU to access Common memory ??? */
+
+/*============================================================*/
+
+static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+    	DPRINTK("hs_proc_setup(%d)\n", sock);
+}
+
+/*============================================================*/
+
+/*
+ * This function is registered with the HD64465 glue code to do a
+ * secondary demux step on the PCMCIA interrupts.  It handles 
+ * mapping the IREQ request from the card to a standard Linux
+ * IRQ, as requested by SocketServices.
+ */
+static int hs_irq_demux(int irq, void *dev)
+{
+    	hs_socket_t *sp = (hs_socket_t *)dev;
+	u_int cscr;
+    	
+    	DPRINTK("hs_irq_demux(irq=%d)\n", irq);
+
+    	if (sp->state.io_irq &&
+	    (cscr = hs_in(sp, CSCR)) & HD64465_PCCCSCR_PIREQ) {
+	    cscr &= ~HD64465_PCCCSCR_PIREQ;
+	    hs_out(sp, cscr, CSCR);
+	    return sp->state.io_irq;
+	}
+	    
+	return irq;
+}
+
+/*============================================================*/
+
+/*
+ * Interrupt handling routine.
+ *
+ * This uses the schedule_task() technique to cause reportable events
+ * such as card insertion and removal to be handled in keventd's
+ * process context.
+ */
+ 
+
+static void hs_events_bh(void *dummy)
+{
+	hs_socket_t *sp;
+	u_int events;
+	int i;
+
+	for (i=0; i<HS_MAX_SOCKETS; i++) {
+	    sp = &hs_sockets[i];
+
+	    spin_lock_irq(&hs_pending_event_lock);
+	    events = sp->pending_events;
+	    sp->pending_events = 0;
+	    spin_unlock_irq(&hs_pending_event_lock);
+	    
+	    if (sp->handler)
+		sp->handler(sp->handler_info, events);
+	}
+}
+
+static struct tq_struct hs_events_task = {
+	routine:	hs_events_bh
+};
+
+static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    	hs_socket_t *sp = (hs_socket_t *)dev;
+	u_int events = 0;
+	u_int cscr;
+	
+	
+	cscr = hs_in(sp, CSCR);
+	
+	DPRINTK("hs_interrupt, cscr=%04x\n", cscr);
+
+	/* check for bus-related changes to be reported to Socket Services */
+	if (cscr & HD64465_PCCCSCR_PCDC) {
+	    /* double-check for a 16-bit card, as we don't support CardBus */
+	    if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) {
+	    	printk(KERN_NOTICE MODNAME
+		    ": socket %d, card not a supported card type or not inserted correctly\n",
+		    hs_sockno(sp));
+		/* Don't do the rest unless a card is present */
+		cscr &= ~(HD64465_PCCCSCR_PCDC|
+		    	  HD64465_PCCCSCR_PRC|
+			  HD64465_PCCCSCR_PBW|
+		    	  HD64465_PCCCSCR_PBD|
+			  HD64465_PCCCSCR_PSC);
+	    } else {
+	    	cscr &= ~HD64465_PCCCSCR_PCDC;
+		events |= SS_DETECT;    	/* card insertion or removal */
+    	    }
+	}
+	if (cscr & HD64465_PCCCSCR_PRC) {
+	    cscr &= ~HD64465_PCCCSCR_PRC;
+	    events |= SS_READY;     	/* ready signal changed */
+	}
+	if (cscr & HD64465_PCCCSCR_PBW) {
+	    cscr &= ~HD64465_PCCCSCR_PSC;
+	    events |= SS_BATWARN;     	/* battery warning */
+	}
+	if (cscr & HD64465_PCCCSCR_PBD) {
+	    cscr &= ~HD64465_PCCCSCR_PSC;
+	    events |= SS_BATDEAD;     	/* battery dead */
+	}
+	if (cscr & HD64465_PCCCSCR_PSC) {
+	    cscr &= ~HD64465_PCCCSCR_PSC;
+	    events |= SS_STSCHG;     	/* STSCHG (status changed) signal */
+	}
+	
+	if (cscr & HD64465_PCCCSCR_PIREQ) {
+	    cscr &= ~HD64465_PCCCSCR_PIREQ;
+
+    	    /* This should have been dealt with during irq demux */	    
+	    printk(KERN_NOTICE MODNAME ": unexpected IREQ from card\n");
+	}
+
+	hs_out(sp, cscr, CSCR);
+
+	if (events) {
+	    /*
+    	     * Arrange for events to be reported to the registered
+	     * event handler function (from CardServices) in a process
+	     * context (keventd) "soon".
+	     */
+	    spin_lock(&hs_pending_event_lock);
+	    sp->pending_events |= events;
+	    spin_unlock(&hs_pending_event_lock);
+	    
+	    schedule_task(&hs_events_task);
+	}
+}
+
+/*============================================================*/
+
+static struct pccard_operations hs_operations = {
+	hs_init,
+	hs_suspend,
+	hs_register_callback,
+	hs_inquire_socket,
+	hs_get_status,
+	hs_get_socket,
+	hs_set_socket,
+	hs_get_io_map,
+	hs_set_io_map,
+	hs_get_mem_map,
+	hs_set_mem_map,
+	hs_proc_setup
+};
+
+static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
+    	    unsigned int ctrl_base)
+{
+    	unsigned short v;
+    	int i, err;
+
+    	memset(sp, 0, sizeof(*sp));
+	sp->irq = irq;
+	sp->mem_base = mem_base;
+	sp->mem_length = 4*HD64465_PCC_WINDOW;	/* 16MB */
+	sp->ctrl_base = ctrl_base;
+	
+	for (i=0 ; i<MAX_IO_WIN ; i++)
+	    sp->io_maps[i].map = i;
+	for (i=0 ; i<MAX_WIN ; i++)
+	    sp->mem_maps[i].map = i;
+	
+	if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0)
+	    return -ENOMEM;
+
+	hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);
+	
+    	if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)
+	    return err;
+    	if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) {
+    	    sp->mem_base = 0;
+	    return -ENOMEM;
+	}
+
+
+	/* According to section 3.2 of the PCMCIA standard, low-voltage
+	 * capable cards must implement cold insertion, i.e. Vpp and
+	 * Vcc set to 0 before card is inserted.
+	 */
+	/*hs_set_voltages(sp, 0, 0);*/
+	
+	/* hi-Z the outputs to the card and set 16MB map mode */
+	v = hs_in(sp, GCR);
+	v &= ~HD64465_PCCGCR_PCCT;  	/* memory-only card */
+	hs_out(sp, v, GCR);
+
+	v = hs_in(sp, GCR);
+	v |= HD64465_PCCGCR_PDRV;   	/* enable outputs to card */
+	hs_out(sp, v, GCR);
+
+	v = hs_in(sp, GCR);
+	v |= HD64465_PCCGCR_PMMOD; 	/* 16MB mapping mode */
+	hs_out(sp, v, GCR);
+
+	v = hs_in(sp, GCR);
+	/* lowest 16MB of Common */
+	v &= ~(HD64465_PCCGCR_PPA25|HD64465_PCCGCR_PPA24); 
+	hs_out(sp, v, GCR);
+	
+	hs_reset_socket(sp, 1);
+
+    	return 0;
+}
+
+static void hs_exit_socket(hs_socket_t *sp)
+{
+    	unsigned short cscier, gcr;
+	
+	/* turn off interrupts in hardware */
+    	cscier = hs_in(sp, CSCIER);
+	cscier = (cscier & IER_MASK) | IER_OFF;
+    	hs_out(sp, cscier, CSCIER);
+	
+	/* hi-Z the outputs to the card */
+    	gcr = hs_in(sp, GCR);
+	gcr &= HD64465_PCCGCR_PDRV;
+	hs_out(sp, gcr, GCR);
+
+    	/* power the card down */
+	hs_set_voltages(sp, 0, 0);
+
+    	if (sp->mem_base != 0)
+	    release_mem_region(sp->mem_base, sp->mem_length);
+	if (sp->irq != 0) {
+	    free_irq(sp->irq, hs_interrupt);
+    	    hd64465_unregister_irq_demux(sp->irq);
+	}
+	if (sp->io_vma != 0)
+	    vfree(sp->io_vma->addr);
+}
+
+
+static int __init init_hs(void)
+{
+	servinfo_t serv;
+	int i;
+	unsigned short v;
+
+    	/*
+	 * Check API version
+	 */
+	pcmcia_get_card_services_info(&serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+	    printk(KERN_NOTICE MODNAME ": Card Services release does not match!\n");
+	    return -ENODEV;
+	}
+
+/*	hd64465_io_debug = 1; */
+	
+	/* Wake both sockets out of STANDBY mode */
+	/* TODO: wait 15ms */
+	v = inw(HD64465_REG_SMSCR);
+	v &= ~(HD64465_SMSCR_PC0ST|HD64465_SMSCR_PC1ST);
+	outw(v, HD64465_REG_SMSCR);
+
+	/* keep power controller out of shutdown mode */
+	v = inb(HD64465_REG_PCC0SCR);
+	v |= HD64465_PCCSCR_SHDN;
+	outb(v, HD64465_REG_PCC0SCR);
+
+    	/* use serial (TPS2206) power controller */
+	v = inb(HD64465_REG_PCC0CSCR);
+	v |= HD64465_PCCCSCR_PSWSEL;
+	outb(v, HD64465_REG_PCC0CSCR);
+
+    	hs_set_voltages(&hs_sockets[0], 0, 0);
+    	hs_set_voltages(&hs_sockets[1], 0, 0);
+	
+	/*
+	 * Setup hs_sockets[] structures and request system resources.
+	 * TODO: on memory allocation failure, power down the socket
+	 *       before quitting.
+	 */
+	i = hs_init_socket(&hs_sockets[0],
+	    HD64465_IRQ_PCMCIA0,
+	    HD64465_PCC0_BASE,
+	    HD64465_REG_PCC0ISR);
+	if (i < 0)
+	    return i;
+	i = hs_init_socket(&hs_sockets[1],
+	    HD64465_IRQ_PCMCIA1,
+	    HD64465_PCC1_BASE,
+	    HD64465_REG_PCC1ISR);
+	if (i < 0)
+	    return i;
+
+/*	hd64465_io_debug = 0; */
+	    
+
+	if (register_ss_entry(HS_MAX_SOCKETS, &hs_operations) != 0) {
+	    for (i=0 ; i<HS_MAX_SOCKETS ; i++)
+		hs_exit_socket(&hs_sockets[i]);
+    	    return -ENODEV;
+	}
+
+	printk(KERN_INFO "HD64465 PCMCIA bridge:\n");
+	for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
+	    hs_socket_t *sp = &hs_sockets[i];
+	    
+	    printk(KERN_INFO "  socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",
+	    	i, sp->mem_base, sp->irq,
+		sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
+	}
+
+    	return 0;
+}
+
+static void __exit exit_hs(void)
+{
+    	u_long flags;
+	int i;
+	
+	save_and_cli(flags);
+
+    	/*
+	 * Release kernel resources
+	 */
+	for (i=0 ; i<HS_MAX_SOCKETS ; i++)
+	    hs_exit_socket(&hs_sockets[i]);
+	unregister_ss_entry(&hs_operations);
+	
+	restore_flags(flags);
+}
+
+module_init(init_hs);
+module_exit(exit_hs);
+
+/*============================================================*/
+/*END*/
diff -urN linux-2.4.2-pre4/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- linux-2.4.2-pre4/drivers/pcmcia/i82365.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/i82365.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/i82365.h linux/drivers/pcmcia/i82365.h
--- linux-2.4.2-pre4/drivers/pcmcia/i82365.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/i82365.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/o2micro.h linux/drivers/pcmcia/o2micro.h
--- linux-2.4.2-pre4/drivers/pcmcia/o2micro.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/o2micro.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/old-yenta.h linux/drivers/pcmcia/old-yenta.h
--- linux-2.4.2-pre4/drivers/pcmcia/old-yenta.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/old-yenta.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/ricoh.h linux/drivers/pcmcia/ricoh.h
--- linux-2.4.2-pre4/drivers/pcmcia/ricoh.h	Tue Jan 25 11:41:20 2000
+++ linux/drivers/pcmcia/ricoh.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- linux-2.4.2-pre4/drivers/pcmcia/rsrc_mgr.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/rsrc_mgr.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h
--- linux-2.4.2-pre4/drivers/pcmcia/rsrc_mgr.h	Sat Sep  2 00:13:49 2000
+++ linux/drivers/pcmcia/rsrc_mgr.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/smc34c90.h linux/drivers/pcmcia/smc34c90.h
--- linux-2.4.2-pre4/drivers/pcmcia/smc34c90.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/smc34c90.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- linux-2.4.2-pre4/drivers/pcmcia/tcic.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/pcmcia/tcic.c	Mon Dec  3 22:29:16 2001
@@ -19,7 +19,7 @@
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU Public License version 2 (the "GPL"), in which
+    terms of the GNU General Public License version 2 (the "GPL"), in which
     case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/tcic.h linux/drivers/pcmcia/tcic.h
--- linux-2.4.2-pre4/drivers/pcmcia/tcic.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/tcic.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/ti113x.h linux/drivers/pcmcia/ti113x.h
--- linux-2.4.2-pre4/drivers/pcmcia/ti113x.h	Mon Jan 29 23:25:52 2001
+++ linux/drivers/pcmcia/ti113x.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/topic.h linux/drivers/pcmcia/topic.h
--- linux-2.4.2-pre4/drivers/pcmcia/topic.h	Fri Sep  3 12:27:58 1999
+++ linux/drivers/pcmcia/topic.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/pcmcia/vg468.h linux/drivers/pcmcia/vg468.h
--- linux-2.4.2-pre4/drivers/pcmcia/vg468.h	Thu Nov 11 16:03:37 1999
+++ linux/drivers/pcmcia/vg468.h	Mon Dec  3 22:29:16 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.4.2-pre4/drivers/s390/block/dasd.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/s390/block/dasd.c	Mon Dec  3 22:29:16 2001
@@ -1113,6 +1113,8 @@
 {
 	struct buffer_head *bh;
 	while ((bh = req->bh) != NULL) {
+                int nsect = bh->b_size >> 9;
+                blk_finished_io (nsect);
 		req->bh = bh->b_reqnext;
 		bh->b_reqnext = NULL;
 		bh->b_end_io (bh, uptodate);
diff -urN linux-2.4.2-pre4/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- linux-2.4.2-pre4/drivers/sbus/audio/amd7930.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/audio/amd7930.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.25 2001/01/08 04:19:16 davem Exp $
+/* $Id: amd7930.c,v 1.26 2001/02/13 01:16:59 davem Exp $
  * drivers/sbus/audio/amd7930.c
  *
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
diff -urN linux-2.4.2-pre4/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- linux-2.4.2-pre4/drivers/sbus/audio/audio.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/audio/audio.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.57 2001/02/02 08:36:55 davem Exp $
+/* $Id: audio.c,v 1.58 2001/02/13 01:16:59 davem Exp $
  * drivers/sbus/audio/audio.c
  *
  * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
diff -urN linux-2.4.2-pre4/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- linux-2.4.2-pre4/drivers/sbus/audio/cs4231.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/audio/cs4231.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.43 2000/02/18 13:49:39 davem Exp $
+/* $Id: cs4231.c,v 1.44 2001/02/13 01:16:59 davem Exp $
  * drivers/sbus/audio/cs4231.c
  *
  * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
diff -urN linux-2.4.2-pre4/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- linux-2.4.2-pre4/drivers/sbus/audio/dbri.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/audio/dbri.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.24 2001/02/02 08:36:55 davem Exp $
+/* $Id: dbri.c,v 1.25 2001/02/13 01:16:59 davem Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
diff -urN linux-2.4.2-pre4/drivers/sbus/audio/dmy.c linux/drivers/sbus/audio/dmy.c
--- linux-2.4.2-pre4/drivers/sbus/audio/dmy.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/audio/dmy.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: dmy.c,v 1.6 2000/12/13 05:06:26 davem Exp $
+/* $Id: dmy.c,v 1.7 2001/02/13 01:16:59 davem Exp $
  * drivers/sbus/audio/dummy.c
  *
  * Copyright 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- linux-2.4.2-pre4/drivers/sbus/char/envctrl.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/envctrl.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.19 2000/11/03 00:37:40 davem Exp $
+/* $Id: envctrl.c,v 1.21 2001/02/13 04:07:38 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -229,7 +229,7 @@
 		printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
 }
 
-/* Function Description: Send the adress for a read access.
+/* Function Description: Send the address for a read access.
  * Return : 0 if not acknowledged, otherwise acknowledged.
  */
 static int envctrl_i2c_read_addr(unsigned char addr)
@@ -255,7 +255,7 @@
 	}
 }
 
-/* Function Description: Send the adress for write mode.  
+/* Function Description: Send the address for write mode.  
  * Return : None.
  */
 static void envctrl_i2c_write_addr(unsigned char addr)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c
--- linux-2.4.2-pre4/drivers/sbus/char/flash.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/flash.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.21 2001/01/11 15:29:36 davem Exp $
+/* $Id: flash.c,v 1.22 2001/02/13 01:17:00 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- linux-2.4.2-pre4/drivers/sbus/char/pcikbd.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/pcikbd.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.50 2001/01/11 15:29:36 davem Exp $
+/* $Id: pcikbd.c,v 1.51 2001/02/13 01:17:00 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- linux-2.4.2-pre4/drivers/sbus/char/rtc.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/rtc.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.24 2001/01/11 15:07:09 davem Exp $
+/* $Id: rtc.c,v 1.25 2001/02/13 01:17:00 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- linux-2.4.2-pre4/drivers/sbus/char/sab82532.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/sab82532.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.54 2000/12/07 04:35:39 anton Exp $
+/* $Id: sab82532.c,v 1.55 2001/02/13 01:17:00 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2134,7 +2134,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.54 $";
+	char *revision = "$Revision: 1.55 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -urN linux-2.4.2-pre4/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- linux-2.4.2-pre4/drivers/sbus/char/su.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/su.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.43 2000/11/15 07:28:09 davem Exp $
+/* $Id: su.c,v 1.44 2001/02/13 01:17:00 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2220,7 +2220,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.43 $";
+	char *revision = "$Revision: 1.44 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -urN linux-2.4.2-pre4/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c
--- linux-2.4.2-pre4/drivers/sbus/char/uctrl.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/uctrl.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: uctrl.c,v 1.9 2000/11/08 05:04:06 davem Exp $
+/* $Id: uctrl.c,v 1.10 2001/02/13 01:17:00 davem Exp $
  * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
  *
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
diff -urN linux-2.4.2-pre4/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c
--- linux-2.4.2-pre4/drivers/sbus/char/vfc_i2c.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/char/vfc_i2c.c	Mon Dec  3 22:29:16 2001
@@ -315,7 +315,7 @@
 		switch(ret) {
 		case XMIT_LAST_BYTE:
 			VFC_I2C_DEBUG_PRINTK(("vfc%d: "
-					      "Reciever ended transmission with "
+					      "Receiver ended transmission with "
 					      " %d bytes remaining\n",
 					      dev->instance, count));
 			ret = 0;
diff -urN linux-2.4.2-pre4/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- linux-2.4.2-pre4/drivers/sbus/sbus.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/sbus/sbus.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.92 2001/01/25 17:15:59 davem Exp $
+/* $Id: sbus.c,v 1.94 2001/02/13 07:34:40 davem Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -67,29 +67,12 @@
 	sdev->ranges_applied = 0;
 
 	base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-	if (base >= SUN_SBUS_BVADDR ||
-	    (sparc_cpu_model != sun4c && sparc_cpu_model != sun4)) {
-		/* OK, we can compute the slot number in a
-		 * straightforward manner.
-		 */
-		if (sparc_cpu_model == sun4u ||
-		    sparc_cpu_model == sun4d)
-			sdev->slot = sdev->reg_addrs[0].which_io;
-		else
-			sdev->slot = sbus_dev_slot(base);
-	} else {
-		int rnum;
 
-		/* Fixups are needed to compute the slot number. */
+	/* Compute the slot number. */
+	if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) {
+		sdev->slot = sbus_dev_slot(base);
+	} else {
 		sdev->slot = sdev->reg_addrs[0].which_io;
-		sdev->reg_addrs[0].phys_addr =
-			sbus_devaddr(sdev->slot, base);
-		for (rnum = 1; rnum < sdev->num_registers; rnum++) {
-			base = (unsigned long)
-				sdev->reg_addrs[rnum].phys_addr;
-			sdev->reg_addrs[rnum].phys_addr =
-				sbus_devaddr(sdev->slot, base);
-		}
 	}
 
 no_regs:
diff -urN linux-2.4.2-pre4/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- linux-2.4.2-pre4/drivers/scsi/NCR5380.c	Fri Jul  7 15:55:24 2000
+++ linux/drivers/scsi/NCR5380.c	Mon Dec  3 22:29:16 2001
@@ -2264,8 +2264,8 @@
 		return -1;
 	}
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-#ifdef READ_OVERRUNS if (p & SR_IO) { c -= 2;
-}
+#ifdef READ_OVERRUNS 
+	if (p & SR_IO) { c -= 2; }
 #endif
 #if (NDEBUG & NDEBUG_DMA)
 printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n",
diff -urN linux-2.4.2-pre4/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- linux-2.4.2-pre4/drivers/scsi/eata.c	Mon Dec  3 22:29:06 2001
+++ linux/drivers/scsi/eata.c	Mon Dec  3 22:29:16 2001
@@ -1,6 +1,9 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      30 Jan 2001 Rev. 6.04 for linux 2.4.1
+ *        + Call pci_resource_start after pci_enable_device.
+ *
  *      25 Jan 2001 Rev. 6.03 for linux 2.4.0
  *        + "check_region" call replaced by "request_region".
  *
@@ -838,9 +841,9 @@
 
       if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
 
-      addr = pci_resource_start (dev, 0);
-
       if (pci_enable_device (dev)) continue;
+
+      addr = pci_resource_start (dev, 0);
 
 #if defined(DEBUG_PCI_DETECT)
       printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n",
diff -urN linux-2.4.2-pre4/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- linux-2.4.2-pre4/drivers/scsi/eata.h	Mon Dec  3 22:29:07 2001
+++ linux/drivers/scsi/eata.h	Mon Dec  3 22:29:16 2001
@@ -13,7 +13,7 @@
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "6.03.00"
+#define EATA_VERSION "6.04.00"
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
diff -urN linux-2.4.2-pre4/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- linux-2.4.2-pre4/drivers/scsi/esp.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/scsi/esp.c	Mon Dec  3 22:29:16 2001
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.98 2000/11/02 22:34:16 davem Exp $
+/* $Id: esp.c,v 1.99 2001/02/13 01:17:01 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.2-pre4/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- linux-2.4.2-pre4/drivers/scsi/sr.c	Sun Jan 28 13:37:50 2001
+++ linux/drivers/scsi/sr.c	Mon Dec  3 22:29:16 2001
@@ -88,7 +88,6 @@
 static int *sr_sizes;
 
 static int *sr_blocksizes;
-static int *sr_hardsizes;
 
 static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
@@ -349,7 +348,7 @@
 	devm = MINOR(SCpnt->request.rq_dev);
 	dev = DEVICE_NR(SCpnt->request.rq_dev);
 
-	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
+	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm));
 
 	if (dev >= sr_template.nr_dev ||
 	    !scsi_CDs[dev].device ||
@@ -783,21 +782,16 @@
 	if (!sr_blocksizes)
 		goto cleanup_sizes;
 
-	sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
-	if (!sr_hardsizes)
-		goto cleanup_blocksizes;
 	/*
 	 * These are good guesses for the time being.
+	 * Don't set sr_hardsizes here! That will prevent reading anything smaller.
 	 */
 	for (i = 0; i < sr_template.dev_max; i++) {
 		sr_blocksizes[i] = 2048;
-		sr_hardsizes[i] = 2048;
         }
 	blksize_size[MAJOR_NR] = sr_blocksizes;
-        hardsect_size[MAJOR_NR] = sr_hardsizes;
 	return 0;
-cleanup_blocksizes:
-	kfree(sr_blocksizes);
+
 cleanup_sizes:
 	kfree(sr_sizes);
 cleanup_cds:
@@ -921,11 +915,8 @@
 
 		kfree(sr_blocksizes);
 		sr_blocksizes = NULL;
-		kfree(sr_hardsizes);
-		sr_hardsizes = NULL;
 	}
 	blksize_size[MAJOR_NR] = NULL;
-        hardsect_size[MAJOR_NR] = NULL;
 	blk_size[MAJOR_NR] = NULL;
 	read_ahead[MAJOR_NR] = 0;
 
diff -urN linux-2.4.2-pre4/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- linux-2.4.2-pre4/drivers/scsi/tmscsim.c	Thu Jan  4 15:25:55 2001
+++ linux/drivers/scsi/tmscsim.c	Mon Dec  3 22:29:16 2001
@@ -3054,7 +3054,4 @@
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
 static Scsi_Host_Template driver_template = DC390_T;
 #include "scsi_module.c"
-#elif defined(MODULE)
-Scsi_Host_Template driver_template = DC390_T;
-#include "scsi_module.c"
 #endif
diff -urN linux-2.4.2-pre4/drivers/sound/Config.in linux/drivers/sound/Config.in
--- linux-2.4.2-pre4/drivers/sound/Config.in	Mon Dec  3 22:29:07 2001
+++ linux/drivers/sound/Config.in	Mon Dec  3 22:29:16 2001
@@ -22,6 +22,7 @@
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI
 dep_tristate '  S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate '  SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
@@ -100,7 +101,6 @@
       bool '      16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_SOUND_GUS16 
       bool '      GUS MAX support' CONFIG_SOUND_GUSMAX
    fi
-   dep_tristate '    Intel ICH audio support' CONFIG_SOUND_ICH $CONFIG_SOUND_OSS
    dep_tristate '    Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS
    dep_tristate '    MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_TRIX" = "y" ]; then
diff -urN linux-2.4.2-pre4/drivers/sound/aci.c linux/drivers/sound/aci.c
--- linux-2.4.2-pre4/drivers/sound/aci.c	Thu Nov 16 12:51:28 2000
+++ linux/drivers/sound/aci.c	Mon Dec  3 22:29:16 2001
@@ -714,5 +714,9 @@
 		release_region(aci_port, 3);
 }
 
+EXPORT_SYMBOL(aci_write_cmd);
+EXPORT_SYMBOL(aci_indexed_cmd);
+EXPORT_SYMBOL(aci_write_cmd_d);
+
 module_init(attach_aci);
 module_exit(unload_aci);
diff -urN linux-2.4.2-pre4/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.2-pre4/drivers/sound/i810_audio.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/sound/i810_audio.c	Mon Dec  3 22:29:17 2001
@@ -879,7 +879,9 @@
 					dmabuf->endcleared = 1;
 				}
 			}			
-			wake_up(&dmabuf->wait);
+			if (dmabuf->count < (signed)dmabuf->dmasize/2) {
+				wake_up(&dmabuf->wait);
+			}
 		}
 	}
 	/* error handling and process wake up for DAC */
@@ -896,10 +898,12 @@
 				   it here, just stop the machine and let the process force hwptr
 				   and swptr to sync */
 				__stop_dac(state);
-				printk("DMA overrun on send\n");
+				printk(KERN_WARNING "i810_audio: DMA overrun on send\n");
 				dmabuf->error++;
 			}
-			wake_up(&dmabuf->wait);
+			if (dmabuf->count < (signed)dmabuf->dmasize/2) {
+				wake_up(&dmabuf->wait);
+			}
 		}
 	}
 }
@@ -1047,7 +1051,7 @@
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
 #endif
-				/* a buffer overrun, we delay the recovery untill next time the
+				/* a buffer overrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have space to record */
 			}
 			if (signal_pending(current)) {
@@ -1144,7 +1148,7 @@
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
 #endif
-				/* a buffer underrun, we delay the recovery untill next time the
+				/* a buffer underrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have data to play */
 			}
 			if (signal_pending(current)) {
@@ -1823,7 +1827,7 @@
 }
 
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
    
 static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
diff -urN linux-2.4.2-pre4/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- linux-2.4.2-pre4/drivers/sound/maestro3.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/sound/maestro3.c	Mon Dec  3 22:29:17 2001
@@ -130,6 +130,7 @@
 #include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
diff -urN linux-2.4.2-pre4/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c
--- linux-2.4.2-pre4/drivers/sound/opl3sa2.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/sound/opl3sa2.c	Mon Dec  3 22:29:17 2001
@@ -894,7 +894,7 @@
 	/* Sanitize isapnp and multiple settings */
 	isapnp = isapnp != 0 ? 1 : 0;
 	multiple = multiple != 0 ? 1 : 0;
-
+	
 	max = (multiple && isapnp) ? OPL3SA2_CARDS_MAX : 1;
 	for(card = 0; card < max; card++, opl3sa2_cards_num++) {
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
@@ -912,7 +912,9 @@
 			break;
 		}
 #endif
-		if(!isapnp) {
+		/* If a user wants an I/O then assume they meant it */
+		
+		if(!isapnp && io == -1 ) {
 			if(io == -1 || irq == -1 || dma == -1 ||
 			   dma2 == -1 || mss_io == -1) {
 				printk(KERN_ERR
diff -urN linux-2.4.2-pre4/drivers/sound/sb.h linux/drivers/sound/sb.h
--- linux-2.4.2-pre4/drivers/sound/sb.h	Wed Sep 27 13:53:56 2000
+++ linux/drivers/sound/sb.h	Mon Dec  3 22:29:17 2001
@@ -137,6 +137,8 @@
 	   void (*midi_input_intr) (int dev, unsigned char data);
 	   void *midi_irq_cookie;		/* IRQ cookie for the midi */
 
+	   spinlock_t lock;
+
 	   struct sb_module_options sbmo;	/* Module options */
 
 	} sb_devc;
diff -urN linux-2.4.2-pre4/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c
--- linux-2.4.2-pre4/drivers/sound/sb_audio.c	Fri Aug 11 08:26:43 2000
+++ linux/drivers/sound/sb_audio.c	Mon Dec  3 22:29:17 2001
@@ -19,8 +19,11 @@
  * Daniel J. Rodriksson: Changes to make sb16 work full duplex.
  *                       Maybe other 16 bit cards in this code could behave
  *                       the same.
+ * Chris Rankin:         Use spinlocks instead of CLI/STI
  */
 
+#include <linux/spinlock.h>
+
 #include "sound_config.h"
 
 #include "sb_mixer.h"
@@ -43,23 +46,22 @@
 		if (mode == OPEN_READ)
 			return -EPERM;
 	}
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (devc->opened)
 	{
-		  restore_flags(flags);
+		  spin_unlock_irqrestore(&devc->lock, flags);
 		  return -EBUSY;
 	}
 	if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
 	{
 		if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
 		{
-			restore_flags(flags);
+		  	spin_unlock_irqrestore(&devc->lock, flags);
 			return -EBUSY;
 		}
 	}
 	devc->opened = mode;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	devc->irq_mode = IMODE_NONE;
 	devc->irq_mode_16 = IMODE_NONE;
@@ -182,8 +184,7 @@
 
 	devc->irq_mode = IMODE_OUTPUT;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x14))		/* 8 bit DAC using DMA */
 	{
 		sb_dsp_command(devc, (unsigned char) (count & 0xff));
@@ -191,7 +192,7 @@
 	}
 	else
 		printk(KERN_WARNING "Sound Blaster:  unable to start DAC.\n");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 	devc->intr_active = 1;
 }
 
@@ -213,8 +214,7 @@
 
 	devc->irq_mode = IMODE_INPUT;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x24))		/* 8 bit ADC using DMA */
 	{
 		sb_dsp_command(devc, (unsigned char) (count & 0xff));
@@ -222,7 +222,7 @@
 	}
 	else
 		printk(KERN_ERR "Sound Blaster:  unable to start ADC.\n");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	devc->intr_active = 1;
 }
@@ -258,12 +258,11 @@
 	sb_devc *devc = audio_devs[dev]->devc;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x40))
 		sb_dsp_command(devc, devc->tconst);
 	sb_dsp_command(devc, DSP_CMD_SPKOFF);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	devc->trigger_bits = 0;
 	return 0;
@@ -274,12 +273,11 @@
 	sb_devc *devc = audio_devs[dev]->devc;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x40))
 		sb_dsp_command(devc, devc->tconst);
 	sb_dsp_command(devc, DSP_CMD_SPKON);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 	devc->trigger_bits = 0;
 	return 0;
 }
@@ -327,10 +325,9 @@
 	unsigned long flags;
 	sb_devc *devc = audio_devs[dev]->devc;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	sb_dsp_reset(devc);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 /*
@@ -353,8 +350,7 @@
 
 	devc->irq_mode = IMODE_OUTPUT;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x48))		/* DSP Block size */
 	{
 		sb_dsp_command(devc, (unsigned char) (count & 0xff));
@@ -370,7 +366,7 @@
 	}
 	else
 		printk(KERN_ERR "Sound Blaster: unable to start DAC.\n");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 	devc->intr_active = 1;
 }
 
@@ -393,8 +389,7 @@
 
 	devc->irq_mode = IMODE_INPUT;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x48))		/* DSP Block size */
 	{
 		sb_dsp_command(devc, (unsigned char) (count & 0xff));
@@ -410,7 +405,7 @@
 	}
 	else
 		printk(KERN_ERR "Sound Blaster:  unable to start ADC.\n");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 	devc->intr_active = 1;
 }
 
@@ -484,8 +479,7 @@
 		if (devc->bits == AFMT_S16_LE)
 			bits = 0x04;	/* 16 bit mode */
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x40))
 		sb_dsp_command(devc, devc->tconst);
 	sb_dsp_command(devc, DSP_CMD_SPKOFF);
@@ -493,7 +487,7 @@
 		sb_dsp_command(devc, 0xa0 | bits);	/* Mono input */
 	else
 		sb_dsp_command(devc, 0xa8 | bits);	/* Stereo input */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	devc->trigger_bits = 0;
 	return 0;
@@ -511,8 +505,7 @@
 	if (devc->model == MDL_SBPRO)
 		sb_mixer_set_stereo(devc, devc->channels == 2);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (sb_dsp_command(devc, 0x40))
 		sb_dsp_command(devc, devc->tconst);
 	sb_dsp_command(devc, DSP_CMD_SPKON);
@@ -536,7 +529,7 @@
 			tmp |= 0x02;
 		sb_setmixer(devc, 0x0e, tmp);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 	devc->trigger_bits = 0;
 	return 0;
 }
@@ -706,21 +699,19 @@
 	}
 
 	/* save value */
-	save_flags (flags);
-	cli ();
+	spin_lock_irqsave(&devc->lock, flags);
 	bits = devc->bits;
 	if (devc->fullduplex)
 		devc->bits = (devc->bits == AFMT_S16_LE) ?
 			AFMT_U8 : AFMT_S16_LE;
-	restore_flags (flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	cnt = count;
 	if (devc->bits == AFMT_S16_LE)
 		cnt >>= 1;
 	cnt--;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
 
@@ -736,7 +727,7 @@
 
 	/* restore real value after all programming */
 	devc->bits = bits;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 
@@ -768,8 +759,7 @@
 		cnt >>= 1;
 	cnt--;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
 
@@ -783,7 +773,7 @@
 	sb_dsp_command(devc, (unsigned char) (cnt & 0xff));
 	sb_dsp_command(devc, (unsigned char) (cnt >> 8));
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 static void sb16_audio_trigger(int dev, int bits)
diff -urN linux-2.4.2-pre4/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- linux-2.4.2-pre4/drivers/sound/sb_common.c	Wed Sep 27 13:53:56 2000
+++ linux/drivers/sound/sb_common.c	Mon Dec  3 22:29:17 2001
@@ -21,12 +21,16 @@
  *
  * 2000/09/18 - got rid of attach_uart401
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * 2001/01/26 - replaced CLI/STI with spinlocks
+ * Chris Rankin <rankinc@zipworld.com.au>
  */
 
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include "sound_config.h"
 #include "sound_firmware.h"
@@ -62,6 +66,7 @@
 
 static int jazz16_base = 0;		/* Not detected */
 static unsigned char jazz16_bits = 0;	/* I/O relocation bits */
+static spinlock_t jazz16_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Logitech Soundman Wave specific initialization code
@@ -251,8 +256,7 @@
 	unsigned long   flags;
 
 	DDB(printk("Entered dsp_get_vers()\n"));
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	devc->major = devc->minor = 0;
 	sb_dsp_command(devc, 0xe1);	/* Get version */
 
@@ -269,8 +273,8 @@
 			}
 		}
 	}
+	spin_unlock_irqrestore(&devc->lock, flags);
 	DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor));
-	restore_flags(flags);
 }
 
 static int sb16_set_dma_hw(sb_devc * devc)
@@ -368,12 +372,11 @@
 	/*
 	 *	Magic wake up sequence by writing to 0x201 (aka Joystick port)
 	 */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&jazz16_lock, flags);
 	outb((0xAF), 0x201);
 	outb((0x50), 0x201);
 	outb((bits), 0x201);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&jazz16_lock, flags);
 }
 
 static int init_Jazz16(sb_devc * devc, struct address_info *hw_config)
@@ -523,6 +526,7 @@
 		return 0;
 	}
 
+	devc->lock = SPIN_LOCK_UNLOCKED;
 	devc->type = hw_config->card_subtype;
 
 	devc->base = hw_config->io_base;
@@ -552,7 +556,9 @@
 	
 	if (devc->sbmo.acer)
 	{
-		cli();
+		unsigned long flags;
+
+		spin_lock_irqsave(&devc->lock, flags);
 		inb(devc->base + 0x09);
 		inb(devc->base + 0x09);
 		inb(devc->base + 0x09);
@@ -564,7 +570,7 @@
 		inb(devc->base + 0x0b);
 		inb(devc->base + 0x09);
 		inb(devc->base + 0x00);
-		sti();
+		spin_unlock_irqrestore(&devc->lock, flags);
 	}
 	/*
 	 * Detect the device
@@ -631,7 +637,7 @@
 		printk(KERN_ERR "sb: Can't allocate memory for device information\n");
 		return 0;
 	}
-	memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc));
+	memcpy(detected_devc, devc, sizeof(sb_devc));
 	MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
 	return 1;
 }
@@ -937,15 +943,14 @@
 
 	if (devc->model == MDL_ESS) return ess_setmixer (devc, port, value);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 	udelay(20);
 	outb(((unsigned char) (value & 0xff)), MIXER_DATA);
 	udelay(20);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 unsigned int sb_getmixer(sb_devc * devc, unsigned int port)
@@ -955,15 +960,14 @@
 
 	if (devc->model == MDL_ESS) return ess_getmixer (devc, port);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
 	udelay(20);
 	val = inb(MIXER_DATA);
 	udelay(20);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	return val;
 }
@@ -986,14 +990,13 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&jazz16_lock, flags);  /* NOT the SB card? */
 
 	outb((addr & 0xff), base + 1);	/* Low address bits */
 	outb((addr >> 8), base + 2);	/* High address bits */
 	outb((val), base);	/* Data */
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&jazz16_lock, flags);
 }
 
 static unsigned char smw_getmem(sb_devc * devc, int base, int addr)
@@ -1001,14 +1004,13 @@
 	unsigned long flags;
 	unsigned char val;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&jazz16_lock, flags);  /* NOT the SB card? */
 
 	outb((addr & 0xff), base + 1);	/* Low address bits */
 	outb((addr >> 8), base + 2);	/* High address bits */
 	val = inb(base);	/* Data */
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&jazz16_lock, flags);
 	return val;
 }
 
@@ -1168,12 +1170,11 @@
 	/*
 	 *	Magic wake up sequence by writing to 0x201 (aka Joystick port)
 	 */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&jazz16_lock, flags);
 	outb(0xAF, 0x201);
 	outb(0x50, 0x201);
 	outb(bits, 0x201);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&jazz16_lock, flags);
 
 	hw_config->name = "Jazz16";
 	smw_midi_init(devc, hw_config);
diff -urN linux-2.4.2-pre4/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- linux-2.4.2-pre4/drivers/sound/sb_ess.c	Mon Jan  1 10:23:21 2001
+++ linux/drivers/sound/sb_ess.c	Mon Dec  3 22:29:17 2001
@@ -186,6 +186,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include "sound_config.h"
 #include "sb_mixer.h"
@@ -524,10 +525,9 @@
 	unsigned long flags;
 	sb_devc *devc = audio_devs[dev]->devc;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	sb_dsp_reset(devc);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	/*
 	 * Audio 2 may still be operational! Creates awful sounds!
@@ -969,8 +969,7 @@
 	unsigned int val;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	outb(((unsigned char) (0x40 & 0xff)), MIXER_ADDR);
 
 	udelay(20);
@@ -978,7 +977,7 @@
 	udelay(20);
 	val |= inb(MIXER_DATA);
 	udelay(20);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	return val;
 }
@@ -1565,8 +1564,7 @@
 printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);
 #endif
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (port >= 0xa0) {
 		ess_write (devc, port, value);
 	} else {
@@ -1576,7 +1574,7 @@
 		outb(((unsigned char) (value & 0xff)), MIXER_DATA);
 		udelay(20);
 	};
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 unsigned int ess_getmixer (sb_devc * devc, unsigned int port)
@@ -1584,8 +1582,7 @@
 	unsigned int val;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	if (port >= 0xa0) {
 		val = ess_read (devc, port);
@@ -1596,7 +1593,7 @@
 		val = inb(MIXER_DATA);
 		udelay(20);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	return val;
 }
diff -urN linux-2.4.2-pre4/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- linux-2.4.2-pre4/drivers/sound/sb_midi.c	Fri Aug 11 08:26:43 2000
+++ linux/drivers/sound/sb_midi.c	Mon Dec  3 22:29:17 2001
@@ -11,6 +11,8 @@
  * for more info.
  */
 
+#include <linux/spinlock.h>
+
 #include "sound_config.h"
 
 #include "sb.h"
@@ -36,15 +38,14 @@
 	if (devc == NULL)
 		return -ENXIO;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	if (devc->opened)
 	{
-		restore_flags(flags);
+		spin_unlock_irqrestore(&devc->lock, flags);
 		return -EBUSY;
 	}
 	devc->opened = 1;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 
 	devc->irq_mode = IMODE_MIDI;
 	devc->midi_broken = 0;
@@ -74,13 +75,12 @@
 	if (devc == NULL)
 		return;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 	sb_dsp_reset(devc);
 	devc->intr_active = 0;
 	devc->input_opened = 0;
 	devc->opened = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 static int sb_midi_out(int dev, unsigned char midi_byte)
@@ -131,14 +131,13 @@
 	if (devc == NULL)
 		return;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&devc->lock, flags);
 
 	data = inb(DSP_READ);
 	if (devc->input_opened)
 		devc->midi_input_intr(devc->my_mididev, data);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&devc->lock, flags);
 }
 
 #define MIDI_SYNTH_NAME	"Sound Blaster Midi"
diff -urN linux-2.4.2-pre4/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.2-pre4/drivers/sound/ymfpci.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/sound/ymfpci.c	Mon Dec  3 22:29:17 2001
@@ -1719,21 +1719,15 @@
 	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-	/* P3: these frags are for Doom. Amasingly, it sets [2,2**11]. */
-	/* P3 */ // printk("ymfpci: ioctl SNDCTL_DSP_SETFRAGMENT 0x%x\n", val);
-
 		dmabuf = &state->wpcm.dmabuf;
 		dmabuf->ossfragshift = val & 0xffff;
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		switch (dmabuf->ossmaxfrags) {
-		case 1:
-			dmabuf->ossfragshift = 12;
-			return 0;
-		default:
-			/* Fragments must be 2K long */
-			dmabuf->ossfragshift = 11;
-			dmabuf->ossmaxfrags = 2;
-		}
+		if (dmabuf->ossfragshift < 4)
+			dmabuf->ossfragshift = 4;
+		if (dmabuf->ossfragshift > 15)
+			dmabuf->ossfragshift = 15;
+		if (dmabuf->ossmaxfrags < 4)
+			dmabuf->ossmaxfrags = 4;
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
diff -urN linux-2.4.2-pre4/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- linux-2.4.2-pre4/drivers/telephony/ixj.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/telephony/ixj.c	Mon Dec  3 22:29:17 2001
@@ -68,7 +68,7 @@
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_PCMCIA
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -186,7 +186,7 @@
 8-9		Hardware Status Register			Read Only
 A-B		Hardware Control Register			Read Write
 C-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write Only
-E-F Host Recieve (Read) Data Buffer Access Port (buffer input)	Read Only
+E-F Host Receive (Read) Data Buffer Access Port (buffer input)	Read Only
 ************************************************************************/
 
 extern __inline__ void ixj_read_HSR(IXJ *j)
@@ -5823,7 +5823,7 @@
 MODULE_DESCRIPTION("Internet Phone/Internet LineJack module - www.quicknet.net");
 MODULE_AUTHOR("Ed Okerson <eokerson@quicknet.net>");
 
-#ifdef CONFIG_PCMCIA
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
 
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
@@ -5999,6 +5999,7 @@
 
 void ixj_config(dev_link_t * link)
 {
+	IXJ *j;
 	client_handle_t handle;
 	ixj_info_t *info;
 	tuple_t tuple;
diff -urN linux-2.4.2-pre4/drivers/usb/acm.c linux/drivers/usb/acm.c
--- linux-2.4.2-pre4/drivers/usb/acm.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/usb/acm.c	Mon Dec  3 22:29:17 2001
@@ -50,7 +50,6 @@
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #undef DEBUG
 #include <linux/usb.h>
diff -urN linux-2.4.2-pre4/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c
--- linux-2.4.2-pre4/drivers/video/bwtwofb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/bwtwofb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: bwtwofb.c,v 1.13 2000/02/14 02:50:25 davem Exp $
+/* $Id: bwtwofb.c,v 1.14 2001/02/13 01:17:14 davem Exp $
  * bwtwofb.c: BWtwo frame buffer driver
  *
  * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/cgfourteenfb.c linux/drivers/video/cgfourteenfb.c
--- linux-2.4.2-pre4/drivers/video/cgfourteenfb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/cgfourteenfb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: cgfourteenfb.c,v 1.8 2000/08/29 07:01:56 davem Exp $
+/* $Id: cgfourteenfb.c,v 1.9 2001/02/13 01:17:14 davem Exp $
  * cgfourteenfb.c: CGfourteen frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- linux-2.4.2-pre4/drivers/video/cgsixfb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/cgsixfb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.23 2000/07/26 23:02:51 davem Exp $
+/* $Id: cgsixfb.c,v 1.24 2001/02/13 01:17:14 davem Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c
--- linux-2.4.2-pre4/drivers/video/cgthreefb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/cgthreefb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: cgthreefb.c,v 1.9 2000/03/19 04:20:44 anton Exp $
+/* $Id: cgthreefb.c,v 1.10 2001/02/13 01:17:14 davem Exp $
  * cgthreefb.c: CGthree frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- linux-2.4.2-pre4/drivers/video/creatorfb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/creatorfb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.32 2000/07/26 23:02:51 davem Exp $
+/* $Id: creatorfb.c,v 1.33 2001/02/13 01:17:14 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/leofb.c linux/drivers/video/leofb.c
--- linux-2.4.2-pre4/drivers/video/leofb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/leofb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: leofb.c,v 1.11 2000/07/26 23:02:52 davem Exp $
+/* $Id: leofb.c,v 1.12 2001/02/13 01:17:15 davem Exp $
  * leofb.c: Leo (ZX) 24/8bit frame buffer driver
  *
  * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/drivers/video/tcxfb.c linux/drivers/video/tcxfb.c
--- linux-2.4.2-pre4/drivers/video/tcxfb.c	Mon Dec  3 22:29:07 2001
+++ linux/drivers/video/tcxfb.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: tcxfb.c,v 1.11 1999/11/19 09:57:21 davem Exp $
+/* $Id: tcxfb.c,v 1.12 2001/02/13 01:17:15 davem Exp $
  * tcxfb.c: TCX 24/8bit frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -urN linux-2.4.2-pre4/fs/dcache.c linux/fs/dcache.c
--- linux-2.4.2-pre4/fs/dcache.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/dcache.c	Mon Dec  3 22:29:17 2001
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/cache.h>
diff -urN linux-2.4.2-pre4/fs/dquot.c linux/fs/dquot.c
--- linux-2.4.2-pre4/fs/dquot.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/dquot.c	Mon Dec  3 22:29:17 2001
@@ -52,7 +52,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 
diff -urN linux-2.4.2-pre4/fs/iobuf.c linux/fs/iobuf.c
--- linux-2.4.2-pre4/fs/iobuf.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/iobuf.c	Mon Dec  3 22:29:17 2001
@@ -8,7 +8,6 @@
 
 #include <linux/iobuf.h>
 #include <linux/slab.h>
-#include <linux/slab.h>
 
 static kmem_cache_t *kiobuf_cachep;
 
diff -urN linux-2.4.2-pre4/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c
--- linux-2.4.2-pre4/fs/openpromfs/inode.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/openpromfs/inode.c	Mon Dec  3 22:29:17 2001
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.13 2000/08/12 13:25:46 davem Exp $
+/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
diff -urN linux-2.4.2-pre4/fs/partitions/Config.in linux/fs/partitions/Config.in
--- linux-2.4.2-pre4/fs/partitions/Config.in	Sun Jul  9 22:21:41 2000
+++ linux/fs/partitions/Config.in	Mon Dec  3 22:29:17 2001
@@ -21,6 +21,7 @@
    bool '  PC BIOS (MSDOS partition tables) support' CONFIG_MSDOS_PARTITION
    if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then
       bool '    BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
+      bool '    Minix subpartition support' CONFIG_MINIX_SUBPARTITION
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
diff -urN linux-2.4.2-pre4/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.4.2-pre4/fs/partitions/check.c	Sun Dec 31 11:06:00 2000
+++ linux/fs/partitions/check.c	Mon Dec  3 22:29:17 2001
@@ -76,7 +76,7 @@
 };
 
 /*
- * disk_name() is used by genhd.c and blkpg.c.
+ * disk_name() is used by partition check code and the md driver.
  * It formats the devicename of the indicated disk into
  * the supplied buffer (of size at least 32), and returns
  * a pointer to that same buffer (for convenience).
diff -urN linux-2.4.2-pre4/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- linux-2.4.2-pre4/fs/partitions/ibm.c	Wed Apr 12 09:47:30 2000
+++ linux/fs/partitions/ibm.c	Mon Dec  3 22:29:17 2001
@@ -1,8 +1,12 @@
 /*
- * File...........: linux/fs/partitions/ibm.c
+ * File...........: linux/fs/partitions/ibm.c      
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes (starts July 2000)
+ * 07/10/00 Fixed detection of CMS formatted disks               
+
  */
 
 #include <linux/fs.h>
@@ -11,9 +15,21 @@
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
-
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/ioctl.h>
+#include <linux/version.h>
 #include <asm/ebcdic.h>
-#include "../../drivers/s390/block/dasd_types.h"
+#include <asm/uaccess.h>
+#include <asm/dasd.h>
+
+#include "ibm.h"
+#include "check.h"
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+/* We hook in when DASD is a module... */
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+#endif /* LINUX_IS_24 */
 
 typedef enum {
   ibm_partition_none = 0,
@@ -25,98 +41,131 @@
 static ibm_partition_t
 get_partition_type ( char * type )
 {
-  static char lnx[5]="LNX1";
-  static char vol[5]="VOL1";
-  static char cms[5]="CMS1";
-  if ( ! strncmp ( lnx, "LNX1",4 ) ) {
-    ASCEBC(lnx,4);
-    ASCEBC(vol,4);
-    ASCEBC(cms,4);
-  }
-  if ( ! strncmp (type,lnx,4) || 
-       ! strncmp (type,"LNX1",4) )
-    return ibm_partition_lnx1;
-  if ( ! strncmp (type,vol,4) )
-    return ibm_partition_vol1;
-  if ( ! strncmp (type,cms,4) )
-    return ibm_partition_cms1;
-  return ibm_partition_none;
+        static char lnx[5]="LNX1";
+        static char vol[5]="VOL1";
+        static char cms[5]="CMS1";
+        if ( ! strncmp ( lnx, "LNX1",4 ) ) {
+                ASCEBC(lnx,4);
+                ASCEBC(vol,4);
+                ASCEBC(cms,4);
+        }
+        if ( ! strncmp (type,lnx,4) ||
+             ! strncmp (type,"LNX1",4) )
+                return ibm_partition_lnx1;
+        if ( ! strncmp (type,vol,4) )
+                return ibm_partition_vol1;
+        if ( ! strncmp (type,cms,4) )
+                return ibm_partition_cms1;
+        return ibm_partition_none;
 }
 
-void
-ibm_partition (struct gendisk *hd, kdev_t dev)
+int 
+ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
+first_part_minor)
 {
 	struct buffer_head *bh;
 	ibm_partition_t partition_type;
-	int di = MINOR(dev) >> PARTN_BITS;
 	char type[5] = {0,};
 	char name[7] = {0,};
-	if ( bh = bread( dev, 
-			 dasd_info[di]->sizes.label_block, 
-			 get_ptable_blocksize(dev) ) ) {
+	struct hd_geometry geo;
+	mm_segment_t old_fs;
+	int blocksize;
+	struct file *filp = NULL;
+	struct inode *inode = NULL;
+	int offset, size;
+
+	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+	if ( blocksize <= 0 ) {
+		return 0;
+	}
+	set_blocksize(dev, blocksize);  /* OUCH !! */
+
+	/* find out offset of volume label (partn table) */
+	inode = get_empty_inode();
+	inode -> i_rdev = dev;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	inode -> i_bdev = bdget(kdev_t_to_nr(dev));
+#endif /* KERNEL_VERSION */
+	filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+	if (!filp)
+		return 0;
+	memset(filp,0,sizeof(struct file));
+	filp ->f_mode = 1; /* read only */
+	blkdev_open(inode,filp);
+	old_fs=get_fs();
+	set_fs(KERNEL_DS);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
+#else
+	filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
+#endif /* KERNEL_VERSION */
+	set_fs(old_fs);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+        blkdev_put(inode->i_bdev,BDEV_FILE);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	blkdev_close(inode,filp);
+#else
+	blkdev_release(inode);
+#endif /* LINUX_VERSION_CODE */
+
+	size = hd -> sizes[MINOR(dev)]<<1;
+	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
 		strncpy ( type,bh -> b_data, 4);
 		strncpy ( name,bh -> b_data + 4, 6);
         } else {
-		return;
+		return 0;
 	}
 	if ( (*(char *)bh -> b_data) & 0x80 ) {
 		EBCASC(name,6);
 	}
 	switch ( partition_type = get_partition_type(type) ) {
-	case ibm_partition_lnx1:
+	case ibm_partition_lnx1: 
+		offset = (geo.start + 1);
 		printk ( "(LNX1)/%6s:",name);
-		add_gd_partition( hd, MINOR(dev) + 1, 
-				  (dasd_info [di]->sizes.label_block + 1) <<
-				  dasd_info [di]->sizes.s2b_shift,
-				  (dasd_info [di]->sizes.blocks -
-				   dasd_info [di]->sizes.label_block - 1) <<
-				  dasd_info [di]->sizes.s2b_shift );
 		break;
 	case ibm_partition_vol1:
+		offset = 0;
+		size = 0;
 		printk ( "(VOL1)/%6s:",name);
 		break;
 	case ibm_partition_cms1:
 		printk ( "(CMS1)/%6s:",name);
 		if (* (((long *)bh->b_data) + 13) == 0) {
-		  /* disk holds a CMS filesystem */
-		  add_gd_partition( hd, MINOR(dev) + 1, 
-				    (dasd_info [di]->sizes.label_block + 1) <<
-				    dasd_info [di]->sizes.s2b_shift,
-				    (dasd_info [di]->sizes.blocks -
-				     dasd_info [di]->sizes.label_block) <<
-				    dasd_info [di]->sizes.s2b_shift );
-		  printk ("(CMS)");
+			/* disk holds a CMS filesystem */
+			offset = (geo.start + 1);
+			printk ("(CMS)");
 		} else {
-		  /* disk is reserved minidisk */
-		  int offset = (*(((long *)bh->b_data) + 13));
-		  int size = (*(((long *)bh->b_data) + 7)) - 1 - 
-		    (*(((long *)bh->b_data) + 13)) *
-		    ((*(((long *)bh->b_data) + 3)) >> 9);
-		  add_gd_partition( hd, MINOR(dev) + 1, 
-				    offset << dasd_info [di]->sizes.s2b_shift,
-				    size << dasd_info [di]->sizes.s2b_shift );
-		  printk ("(MDSK)");
+			/* disk is reserved minidisk */
+			// mdisk_setup_data.size[i] =
+			// (label[7] - 1 - label[13]) *
+			// (label[3] >> 9) >> 1;
+			long *label=(long*)bh->b_data;
+			blocksize = label[3];
+			offset = label[13];
+			size = (label[7]-1)*(blocksize>>9); 
+			printk ("(MDSK)");
 		}
 		break;
 	case ibm_partition_none:
 		printk ( "(nonl)/      :");
-/*
-		printk ( "%d %d %d ", MINOR(dev) + 1, 
-			 (dasd_info [di]->sizes.label_block + 1) <<
-			 dasd_info [di]->sizes.s2b_shift,
-			 (dasd_info [di]->sizes.blocks -
-			  dasd_info [di]->sizes.label_block - 1) <<
-			 dasd_info [di]->sizes.s2b_shift );
-*/
-		add_gd_partition( hd, MINOR(dev) + 1, 
-				  (dasd_info [di]->sizes.label_block + 1) <<
-				  dasd_info [di]->sizes.s2b_shift,
-				  (dasd_info [di]->sizes.blocks -
-				   dasd_info [di]->sizes.label_block - 1) <<
-				  dasd_info [di]->sizes.s2b_shift );
+		offset = (geo.start+1);
 		break;
+	default:
+		offset = 0;
+		size = 0;
+		
 	}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	add_gd_partition( hd, MINOR(dev), 0,size);
+	add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
+			  size-offset*(blocksize>>9));
+#else
+	add_partition( hd, MINOR(dev), 0,size,0);
+	add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
+			  size-offset*(blocksize>>9) ,0 );
+#endif /* LINUX_VERSION */
 	printk ( "\n" );
 	bforget(bh);
+	return 1;
 }
 
diff -urN linux-2.4.2-pre4/fs/partitions/ibm.h linux/fs/partitions/ibm.h
--- linux-2.4.2-pre4/fs/partitions/ibm.h	Wed Apr 12 09:47:30 2000
+++ linux/fs/partitions/ibm.h	Mon Dec  3 22:29:17 2001
@@ -1 +1 @@
-void ibm_partition (struct gendisk *hd, kdev_t dev);
+int ibm_partition(struct gendisk *, kdev_t, unsigned long, int);
diff -urN linux-2.4.2-pre4/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- linux-2.4.2-pre4/fs/partitions/msdos.c	Mon Jan 29 13:16:00 2001
+++ linux/fs/partitions/msdos.c	Mon Dec  3 22:29:17 2001
@@ -68,6 +68,23 @@
 }
 
 /*
+ * partition_name() formats the short partition name into the supplied
+ * buffer, and returns a pointer to that buffer.
+ * Used by several partition types which makes conditional inclusion messy,
+ * use __attribute__ ((unused)) instead.
+ */
+static char __attribute__ ((unused))
+	*partition_name (struct gendisk *hd, int minor, char *buf)
+{
+#ifdef CONFIG_DEVFS_FS
+	sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1)));
+	return buf;
+#else
+	return disk_name(hd, minor, buf);
+#endif
+}
+
+/*
  * Create devices for each logical partition in an extended partition.
  * The logical partitions form a linked list, with each entry being
  * a partition table with two entries.  The first entry
@@ -194,23 +211,27 @@
 	struct buffer_head *bh;
 	struct solaris_x86_vtoc *v;
 	struct solaris_x86_slice *s;
+	int mask = (1 << hd->minor_shift) - 1;
 	int i;
 	char buf[40];
 
 	if(!(bh = get_partition_table_block(hd, minor, 0)))
 		return;
 	v = (struct solaris_x86_vtoc *)(bh->b_data + 512);
-	if(v->v_sanity != SOLARIS_X86_VTOC_SANE) {
+	if(le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
 		brelse(bh);
 		return;
 	}
-	printk(" %s: <solaris:", disk_name(hd, minor, buf));
-	if(v->v_version != 1) {
-		printk("  cannot handle version %ld vtoc>\n", v->v_version);
+	printk(" %s: <solaris:", partition_name(hd, minor, buf));
+	if(le32_to_cpu(v->v_version) != 1) {
+		printk("  cannot handle version %d vtoc>\n",
+			le32_to_cpu(v->v_version));
 		brelse(bh);
 		return;
 	}
 	for(i=0; i<SOLARIS_X86_NUMSLICE; i++) {
+		if ((current_minor & mask) == 0)
+			break;
 		s = &v->v_slice[i];
 
 		if (s->s_size == 0)
@@ -220,7 +241,8 @@
 		 * one but add_gd_partition starts relative to sector
 		 * zero of the disk.  Therefore, must add the offset
 		 * of the current partition */
-		add_gd_partition(hd, current_minor, s->s_start+offset, s->s_size);
+		add_gd_partition(hd, current_minor, le32_to_cpu(s->s_start)+offset,
+				 le32_to_cpu(s->s_size));
 		current_minor++;
 	}
 	brelse(bh);
@@ -237,21 +259,22 @@
 	for (lin_p = hd->part + 1 + minor;
 	     lin_p - hd->part - minor < current_minor; lin_p++) {
 			/* no relationship -> try again */
-		if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset ||
-		    lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size)
+		if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) ||
+		    lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size))
 			continue;	
 			/* equal -> no need to add */
-		if (lin_p->start_sect == bsd_p->p_offset && 
-			lin_p->nr_sects == bsd_p->p_size) 
+		if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && 
+			lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) 
 			return;
 			/* bsd living within dos partition */
-		if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect 
-			+ lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) {
+		if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect 
+			+ lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) {
 #ifdef DEBUG_BSD_DISKLABEL
 			printk("w: %d %ld+%ld,%d+%d", 
 				lin_p - hd->part, 
 				lin_p->start_sect, lin_p->nr_sects, 
-				bsd_p->p_offset, bsd_p->p_size);
+				le32_to_cpu(bsd_p->p_offset),
+				le32_to_cpu(bsd_p->p_size));
 #endif
 			break;
 		}
@@ -259,14 +282,15 @@
 #ifdef DEBUG_BSD_DISKLABEL
 		printk("???: %d %ld+%ld,%d+%d",
 			lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
-			bsd_p->p_offset, bsd_p->p_size);
+			le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size));
 #endif
 		printk("???");
 		return;
 	} /* if the bsd partition is not currently known to linux, we end
 	   * up here 
 	   */
-	add_gd_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size);
+	add_gd_partition(hd, current_minor, le32_to_cpu(bsd_p->p_offset),
+			 le32_to_cpu(bsd_p->p_size));
 	current_minor++;
 }
 
@@ -285,20 +309,20 @@
 	if (!(bh = get_partition_table_block(hd, minor, 0)))
 		return;
 	l = (struct bsd_disklabel *) (bh->b_data+512);
-	if (l->d_magic != BSD_DISKMAGIC) {
+	if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
 		brelse(bh);
 		return;
 	}
-	printk(" %s:", disk_name(hd, minor, buf));
+	printk(" %s:", partition_name(hd, minor, buf));
 	printk((type == OPENBSD_PARTITION) ? " <openbsd:" :
 	       (type == NETBSD_PARTITION) ? " <netbsd:" : " <bsd:");
 
 	max_partitions = ((type == OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS
 			                              : BSD_MAXPARTITIONS);
-	if (l->d_npartitions < max_partitions)
-		max_partitions = l->d_npartitions;
+	if (le16_to_cpu(l->d_npartitions) < max_partitions)
+		max_partitions = le16_to_cpu(l->d_npartitions);
 	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
-		if ((current_minor & mask) >= (4 + hd->max_p))
+		if ((current_minor & mask) == 0)
 			break;
 
 		if (p->p_fstype != BSD_FS_UNUSED) 
@@ -332,7 +356,7 @@
 		brelse(bh);
 		return;
 	}
-	printk(" %s: <unixware:", disk_name(hd, minor, buf));
+	printk(" %s: <unixware:", partition_name(hd, minor, buf));
 	p = &l->vtoc.v_slice[1];
 	/* I omit the 0th slice as it is the same as whole disk. */
 	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
@@ -352,6 +376,49 @@
 }
 #endif
 
+#ifdef CONFIG_MINIX_SUBPARTITION
+/*
+ * Minix 2.0.0/2.0.2 subpartition support.
+ * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
+ * Rajeev V. Pillai    <rajeevvp@yahoo.com>
+ */
+static void minix_partition(struct gendisk *hd, int minor)
+{
+	struct buffer_head *bh;
+	struct partition *p;
+	int mask = (1 << hd->minor_shift) - 1;
+	int i;
+	char buf[40];
+
+	if (!(bh = get_partition_table_block(hd, minor, 0)))
+		return;
+	bh->b_state = 0;
+
+	p = (struct partition *)(bh->b_data + 0x1be);
+
+	/* The first sector of a Minix partition can have either
+	 * a secondary MBR describing its subpartitions, or
+	 * the normal boot sector. */
+	if ((*(__u16 *) (bh->b_data + 510)) != cpu_to_le16(MSDOS_LABEL_MAGIC) &&
+	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
+
+		printk(" %s: <minix:", partition_name(hd, minor, buf));
+		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
+			if ((current_minor & mask) == 0)
+				break;
+			/* add each partition in use */
+			if (SYS_IND(p) == MINIX_PARTITION) {
+				add_gd_partition(hd, current_minor,
+					      START_SECT(p), NR_SECTS(p));
+				current_minor++;
+			}
+		}
+		printk(" >\n");
+	}
+	brelse(bh);
+}
+#endif /* CONFIG_MINIX_SUBPARTITION */
+ 
 int msdos_partition(struct gendisk *hd, kdev_t dev,
 		    unsigned long first_sector, int first_part_minor) {
 	int i, minor = current_minor = first_part_minor;
@@ -499,6 +566,11 @@
 		    SYS_IND(p) == NETBSD_PARTITION ||
 		    SYS_IND(p) == OPENBSD_PARTITION)
 			bsd_disklabel_partition(hd, minor, SYS_IND(p));
+#endif
+#ifdef CONFIG_MINIX_SUBPARTITION
+		if (SYS_IND(p) == MINIX_PARTITION) {
+			minix_partition(hd, minor);
+		}
 #endif
 #ifdef CONFIG_UNIXWARE_DISKLABEL
 		if (SYS_IND(p) == UNIXWARE_PARTITION)
diff -urN linux-2.4.2-pre4/fs/partitions/osf.c linux/fs/partitions/osf.c
--- linux-2.4.2-pre4/fs/partitions/osf.c	Wed Feb 16 15:42:06 2000
+++ linux/fs/partitions/osf.c	Mon Dec  3 22:29:17 2001
@@ -62,21 +62,21 @@
 	}
 	label = (struct disklabel *) (bh->b_data+64);
 	partition = label->d_partitions;
-	if (label->d_magic != DISKLABELMAGIC) {
+	if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
 		brelse(bh);
 		return 0;
 	}
-	if (label->d_magic2 != DISKLABELMAGIC) {
+	if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
 		brelse(bh);
 		return 0;
 	}
-	for (i = 0 ; i < label->d_npartitions; i++, partition++) {
+	for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) {
 		if ((current_minor & mask) == 0)
 		        break;
-		if (partition->p_size)
+		if (le32_to_cpu(partition->p_size))
 			add_gd_partition(hd, current_minor,
-				first_sector+partition->p_offset,
-				partition->p_size);
+				first_sector+le32_to_cpu(partition->p_offset),
+				le32_to_cpu(partition->p_size));
 		current_minor++;
 	}
 	printk("\n");
diff -urN linux-2.4.2-pre4/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- linux-2.4.2-pre4/fs/reiserfs/namei.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/reiserfs/namei.c	Mon Dec  3 22:29:17 2001
@@ -15,6 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/bitops.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
diff -urN linux-2.4.2-pre4/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- linux-2.4.2-pre4/fs/reiserfs/tail_conversion.c	Mon Jan 15 15:31:19 2001
+++ linux/fs/reiserfs/tail_conversion.c	Mon Dec  3 22:29:17 2001
@@ -92,7 +92,7 @@
     /* Move bytes from the direct items to the new unformatted node
        and delete them. */
     while (1)  {
-	int item_len, first_direct;
+	int tail_size;
 
 	/* end_key.k_offset is set so, that we will always have found
            last item of the file */
@@ -103,13 +103,11 @@
 #ifdef CONFIG_REISERFS_CHECK
 	if (!is_direct_le_ih (p_le_ih))
 	    reiserfs_panic (sb, "vs-14055: direct2indirect: "
-			    "direct item expected, found %h", p_le_ih);
+			    "direct item expected(%k), found %h", 
+				&end_key, p_le_ih);
 #endif
-	if ((le_ih_k_offset (p_le_ih) & (n_blk_size - 1)) == 1)
-	    first_direct = 1;
-	else
-	    first_direct = 0;
-	item_len = le16_to_cpu (p_le_ih->ih_item_len);
+	tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
+	    + ih_item_len(p_le_ih) - 1;
 
 	/* we only send the unbh pointer if the buffer is not up to date.
 	** this avoids overwriting good data from writepage() with old data
@@ -123,7 +121,7 @@
 	n_retval = reiserfs_delete_item (th, path, &end_key, inode, 
 	                                 up_to_date_bh) ;
 
-	if (first_direct && item_len == n_retval)
+	if (tail_size == n_retval)
 	    // done: file does not have direct items anymore
 	    break;
 
diff -urN linux-2.4.2-pre4/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- linux-2.4.2-pre4/fs/smbfs/ChangeLog	Mon Aug 14 13:31:10 2000
+++ linux/fs/smbfs/ChangeLog	Mon Dec  3 22:29:17 2001
@@ -1,5 +1,14 @@
 ChangeLog for smbfs.
 
+2001-02-10 Urban Widmark <urban@teststation.com>
+
+	* dir.c: replace non-bigmem safe cache with cache code from ncpfs
+	  and fix some other bigmem bugs in smbfs.
+	* inode.c: root dentry not properly initialized
+	* proc.c, sock.c: adjust max parameters & max data to follow max_xmit
+	  lots of servers were having find_next trouble with this.
+	* proc.c: use documented write method of truncating (NetApp fix)
+
 2000-08-14 Urban Widmark <urban@svenskatest.se>
 
 	* dir.c: support case sensitive shares
@@ -31,7 +40,7 @@
 
 	* *.c: replace ugly #ifdef's with less ugly debug macros.
 
-2000-01-?? cpg@aladdin.de
+2000-01-03 Christian Groessler <cpg@aladdin.de>
 
 	* proc.c: added posix semantics for unlink
 
diff -urN linux-2.4.2-pre4/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- linux-2.4.2-pre4/fs/smbfs/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/smbfs/Makefile	Mon Dec  3 22:29:17 2001
@@ -20,5 +20,6 @@
 #EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE
 #EXTRA_CFLAGS += -DDEBUG_SMB_MALLOC
 #EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP
+#EXTRA_CFLAGS += -Werror
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.2-pre4/fs/smbfs/cache.c linux/fs/smbfs/cache.c
--- linux-2.4.2-pre4/fs/smbfs/cache.c	Wed Nov  8 19:01:34 2000
+++ linux/fs/smbfs/cache.c	Mon Dec  3 22:29:17 2001
@@ -4,8 +4,7 @@
  * Copyright (C) 1997 by Bill Hawes
  *
  * Routines to support directory cacheing using the page cache.
- * Right now this only works for smbfs, but will be generalized
- * for use with other filesystems.
+ * This cache code is almost directly taken from ncpfs.
  *
  * Please add a note about your changes to smbfs in the ChangeLog file.
  */
@@ -22,271 +21,222 @@
 
 #include "smb_debug.h"
 
-
-static inline struct address_space * 
-get_cache_inode(struct cache_head *cachep)
-{
-	return page_cache_entry((unsigned long) cachep)->mapping;
-}
-
 /*
- * Try to reassemble the old dircache. If we fail - set ->valid to 0.
- * In any case, get at least the page at offset 0 (with ->valid==0 if
- * the old one didn't make it, indeed).
+ * Force the next attempt to use the cache to be a timeout.
+ * If we can't find the page that's fine, it will cause a refresh.
  */
-struct cache_head *
-smb_get_dircache(struct dentry * dentry)
+void
+smb_invalid_dir_cache(struct inode * dir)
 {
-	struct address_space * mapping = &dentry->d_inode->i_data;
-	struct cache_head * cachep = NULL;
-	struct page *page;
-
-	page = find_lock_page(mapping, 0);
-	if (!page) {
-		/* Sorry, not even page 0 around */
-		page = grab_cache_page(mapping, 0);
-		if (!page)
-			goto out;
-		cachep = kmap(page);
-		memset((char*)cachep, 0, PAGE_SIZE);
+	struct smb_sb_info *server = server_from_inode(dir);
+	union  smb_dir_cache *cache = NULL;
+	struct page *page = NULL;
+
+	page = grab_cache_page(&dir->i_data, 0);
+	if (!page)
 		goto out;
-	}
-	cachep = kmap(page);
-	if (cachep->valid) {
-		/*
-		 * OK, at least the page 0 survived and seems to be promising.
-		 * Let's try to reassemble the rest.
-		 */
-		struct cache_index * index = cachep->index;
-		unsigned long offset;
-		int i;
-
-		for (offset = 0, i = 0; i < cachep->pages; i++, index++) {
-			offset += PAGE_SIZE;
-			page = find_lock_page(mapping,offset>>PAGE_CACHE_SHIFT);
-			if (!page) {
-				/* Alas, poor Yorick */
-				cachep->valid = 0;
-				goto out;
-			}
-			index->block = kmap(page);
-		}
-	}
-out:
-	return cachep;
-}
 
-/*
- * Unlock and release the data blocks.
- */
-static void
-smb_free_cache_blocks(struct cache_head * cachep)
-{
-	struct cache_index * index = cachep->index;
-	struct page * page;
-	int i;
-
-	VERBOSE("freeing %d blocks\n", cachep->pages);
-	for (i = 0; i < cachep->pages; i++, index++) {
-		if (!index->block)
-			continue;
-		page = page_cache_entry((unsigned long) index->block);
-		index->block = NULL;
-		kunmap(page);
-		UnlockPage(page);
-		page_cache_release(page);
-	}
-}
+	if (!Page_Uptodate(page))
+		goto out_unlock;
+
+	cache = kmap(page);
+	cache->head.time = jiffies - SMB_MAX_AGE(server);
 
-/*
- * Unlocks and releases the dircache.
- */
-void
-smb_free_dircache(struct cache_head * cachep)
-{
-	struct page *page;
-	VERBOSE("freeing cache\n");
-	smb_free_cache_blocks(cachep);
-	page = page_cache_entry((unsigned long) cachep);
 	kunmap(page);
+	SetPageUptodate(page);
+out_unlock:
 	UnlockPage(page);
 	page_cache_release(page);
+out:
 }
 
 /*
- * Initializes the dircache. We release any existing data blocks,
- * and then clear the cache_head structure.
+ * Mark all dentries for 'parent' as invalid, forcing them to be re-read
  */
 void
-smb_init_dircache(struct cache_head * cachep)
+smb_invalidate_dircache_entries(struct dentry *parent)
 {
-	VERBOSE("initializing cache, %d blocks\n", cachep->pages);
-	smb_free_cache_blocks(cachep);
-	memset(cachep, 0, sizeof(struct cache_head));
+	struct smb_sb_info *server = server_from_dentry(parent);
+	struct list_head *next;
+	struct dentry *dentry;
+
+	spin_lock(&dcache_lock);
+	next = parent->d_subdirs.next;
+	while (next != &parent->d_subdirs) {
+		dentry = list_entry(next, struct dentry, d_child);
+		dentry->d_fsdata = NULL;
+		smb_age_dentry(server, dentry);
+		next = next->next;
+	}
+	spin_unlock(&dcache_lock);
 }
 
-/*
- * Add a new entry to the cache.  This assumes that the
- * entries are coming in order and are added to the end.
- */
-void
-smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
-			off_t fpos)
-{
-	struct address_space * mapping = get_cache_inode(cachep);
-	struct cache_index * index;
-	struct cache_block * block;
-	struct page *page;
-	unsigned long page_off;
-	unsigned int nent, offset, len = entry->len;
-	unsigned int needed = len + sizeof(struct cache_entry);
-
-	VERBOSE("cache %p, status %d, adding %.*s at %ld\n",
-		mapping, cachep->status, entry->len, entry->name, fpos);
 
+static int
+smb_d_validate(struct dentry *dentry)
+{
+	unsigned long dent_addr = (unsigned long) dentry;
+	unsigned long min_addr = PAGE_OFFSET;
+	unsigned long align_mask = 0x0F;
+	unsigned int len;
+	int valid = 0;
+
+	if (dent_addr < min_addr)
+		goto bad_addr;
+	if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
+		goto bad_addr;
+	if ((dent_addr & ~align_mask) != dent_addr)
+		goto bad_align;
+	if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
+						       sizeof(struct dentry))))
+		goto bad_addr;
 	/*
-	 * Don't do anything if we've had an error ...
+	 * Looks safe enough to dereference ...
 	 */
-	if (cachep->status)
+	len = dentry->d_name.len;
+	if (len > SMB_MAXPATHLEN)
 		goto out;
-
-	index = &cachep->index[cachep->idx];
-	if (!index->block)
-		goto get_block;
-
-	/* space available? */
-	if (needed < index->space) {
-	add_entry:
-		nent = index->num_entries;
-		index->num_entries++;
-		index->space -= needed;
-		offset = index->space + 
-			 index->num_entries * sizeof(struct cache_entry);
-		block = index->block;
-		memcpy(&block->cb_data.names[offset], entry->name, len);
-		block->cb_data.table[nent].namelen = len;
-		block->cb_data.table[nent].offset = offset;
-		block->cb_data.table[nent].ino = entry->ino;
-		cachep->entries++;
-
-		VERBOSE("added entry %.*s, len=%d, pos=%ld, entries=%d\n",
-			entry->len, entry->name, len, fpos, cachep->entries);
-		return;
-	}
-	/*
-	 * This block is full ... advance the index.
-	 */
-	cachep->idx++;
-	if (cachep->idx > NINDEX) /* not likely */
-		goto out_full;
-	index++;
 	/*
-	 * Get the next cache block. We don't care for its contents.
+	 * Note: d_validate doesn't dereference the parent pointer ...
+	 * just combines it with the name hash to find the hash chain.
 	 */
-get_block:
-	cachep->pages++;
-	page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
-	page = grab_cache_page(mapping, page_off>>PAGE_CACHE_SHIFT);
-	if (page) {
-		block = kmap(page);
-		index->block = block;
-		index->space = PAGE_SIZE;
-		goto add_entry;
-	}
-	/*
-	 * On failure, just set the return status ...
-	 */
-out_full:
-	cachep->status = -ENOMEM;
+	valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
 out:
-	return;
-}
+	return valid;
 
-int
-smb_find_in_cache(struct cache_head * cachep, off_t pos, 
-		struct cache_dirent *entry)
-{
-	struct cache_index * index = cachep->index;
-	struct cache_block * block;
-	unsigned int i, nent, offset = 0;
-	off_t next_pos = 2;
-
-	VERBOSE("smb_find_in_cache: cache %p, looking for pos=%ld\n",
-		cachep, pos);
-	for (i = 0; i < cachep->pages; i++, index++)
-	{
-		if (pos < next_pos)
-			break;
-		nent = pos - next_pos;
-		next_pos += index->num_entries;
-		if (pos >= next_pos)
-			continue;
-		/*
-		 * The entry is in this block. Note: we return
-		 * then name as a reference with _no_ null byte.
-		 */
-		block = index->block;
-		entry->ino = block->cb_data.table[nent].ino;
-		entry->len = block->cb_data.table[nent].namelen;
-		offset = block->cb_data.table[nent].offset;
-		entry->name = &block->cb_data.names[offset];
-
-		VERBOSE("found %.*s, len=%d, pos=%ld\n",
-			entry->len, entry->name, entry->len, pos);
-		break;
-	}
-	return offset;
+bad_addr:
+	printk(KERN_ERR "smb_d_validate: invalid address %lx\n", dent_addr);
+	goto out;
+bad_align:
+	printk(KERN_ERR "smb_d_validate: unaligned address %lx\n", dent_addr);
+	goto out;
 }
 
-int
-smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
+/*
+ * dget, but require that fpos and parent matches what the dentry contains.
+ * dentry is not known to be a valid pointer at entry.
+ */
+struct dentry *
+smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 {
-	struct inode * inode = dentry->d_inode;
-	int result;
+	struct dentry *dent = dentry;
+	struct list_head *next;
 
-	VERBOSE("smb_refill_dircache: cache %s/%s, blocks=%d\n",
-		DENTRY_PATH(dentry), cachep->pages);
-	/*
-	 * Fill the cache, starting at position 2.
-	 */
-retry:
-	inode->u.smbfs_i.cache_valid |= SMB_F_CACHEVALID;
-	result = smb_proc_readdir(dentry, 2, cachep);
-	if (result < 0)
-	{
-		PARANOIA("readdir failed, result=%d\n", result);
-		goto out;
+	if (smb_d_validate(dent)) {
+		if (dent->d_parent == parent &&
+		    (unsigned long)dent->d_fsdata == fpos) {
+			if (!dent->d_inode) {
+				dput(dent);
+				dent = NULL;
+			}
+			return dent;
+		}
+		dput(dent);
 	}
 
-	/*
-	 * Check whether the cache was invalidated while
-	 * we were doing the scan ...
-	 */
-	if (!(inode->u.smbfs_i.cache_valid & SMB_F_CACHEVALID))
-	{
-		PARANOIA("cache invalidated, retrying\n");
-		goto retry;
+	/* If a pointer is invalid, we search the dentry. */
+	spin_lock(&dcache_lock);
+	next = parent->d_subdirs.next;
+	while (next != &parent->d_subdirs) {
+		dent = list_entry(next, struct dentry, d_child);
+		if ((unsigned long)dent->d_fsdata == fpos) {
+			if (dent->d_inode)
+				dget_locked(dent);
+			else
+				dent = NULL;
+			goto out_unlock;
+		}
+		next = next->next;
 	}
+	dent = NULL;
+out_unlock:
+	spin_unlock(&dcache_lock);
+	return dent;
+}
+
+
+/*
+ * Create dentry/inode for this file and add it to the dircache.
+ */
+int
+smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+	       struct smb_cache_control *ctrl, struct qstr *qname,
+	       struct smb_fattr *entry)
+{
+	struct dentry *newdent, *dentry = filp->f_dentry;
+	struct inode *newino, *inode = dentry->d_inode;
+	struct smb_cache_control ctl = *ctrl;
+	int valid = 0;
+	ino_t ino = 0;
+
+	qname->hash = full_name_hash(qname->name, qname->len);
+
+	if (dentry->d_op && dentry->d_op->d_hash)
+		if (dentry->d_op->d_hash(dentry, qname) != 0)
+			goto end_advance;
+
+	newdent = d_lookup(dentry, qname);
+
+	if (!newdent) {
+		newdent = d_alloc(dentry, qname);
+		if (!newdent)
+			goto end_advance;
+	} else
+		memcpy((char *) newdent->d_name.name, qname->name,
+		       newdent->d_name.len);
+
+	if (!newdent->d_inode) {
+		smb_renew_times(newdent);
+		entry->f_ino = iunique(inode->i_sb, 2);
+		newino = smb_iget(inode->i_sb, entry);
+		if (newino) {
+			smb_new_dentry(newdent);
+			d_add(newdent, newino);
+		}
+	} else
+		smb_set_inode_attr(newdent->d_inode, entry);
 
-	result = cachep->status;
-	if (!result)
-	{
-		cachep->valid = 1;
+        if (newdent->d_inode) {
+		ino = newdent->d_inode->i_ino;
+		newdent->d_fsdata = (void *) ctl.fpos;
+		smb_new_dentry(newdent);
 	}
-	VERBOSE("cache %s/%s status=%d, entries=%d\n",
-		DENTRY_PATH(dentry), cachep->status, cachep->entries);
-out:
-	return result;
-}
 
-void
-smb_invalid_dir_cache(struct inode * dir)
-{
-	/*
-	 * Get rid of any unlocked pages, and clear the
-	 * 'valid' flag in case a scan is in progress.
-	 */
-	invalidate_inode_pages(dir);
-	dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
-	dir->u.smbfs_i.oldmtime = 0;
+	if (ctl.idx >= SMB_DIRCACHE_SIZE) {
+		if (ctl.page) {
+			kunmap(ctl.page);
+			SetPageUptodate(ctl.page);
+			UnlockPage(ctl.page);
+			page_cache_release(ctl.page);
+		}
+		ctl.cache = NULL;
+		ctl.idx  -= SMB_DIRCACHE_SIZE;
+		ctl.ofs  += 1;
+		ctl.page  = grab_cache_page(&inode->i_data, ctl.ofs);
+		if (ctl.page)
+			ctl.cache = kmap(ctl.page);
+	}
+	if (ctl.cache) {
+		ctl.cache->dentry[ctl.idx] = newdent;
+		valid = 1;
+	}
+	dput(newdent);
+
+end_advance:
+	if (!valid)
+		ctl.valid = 0;
+	if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
+		if (!ino)
+			ino = find_inode_number(dentry, qname);
+		if (!ino)
+			ino = iunique(inode->i_sb, 2);
+		ctl.filled = filldir(dirent, qname->name, qname->len,
+				     filp->f_pos, ino, DT_UNKNOWN);
+		if (!ctl.filled)
+			filp->f_pos += 1;
+	}
+	ctl.fpos += 1;
+	ctl.idx  += 1;
+	*ctrl = ctl;
+	return (ctl.valid || !ctl.filled);
 }
diff -urN linux-2.4.2-pre4/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- linux-2.4.2-pre4/fs/smbfs/dir.c	Sun Dec 10 08:48:18 2000
+++ linux/fs/smbfs/dir.c	Mon Dec  3 22:29:17 2001
@@ -19,8 +19,6 @@
 
 #include "smb_debug.h"
 
-#define SMBFS_MAX_AGE 5*HZ
-
 static int smb_readdir(struct file *, void *, filldir_t);
 static int smb_dir_open(struct inode *, struct file *);
 
@@ -52,27 +50,39 @@
 	setattr:	smb_notify_change,
 };
 
+/*
+ * Read a directory, using filldir to fill the dirent memory.
+ * smb_proc_readdir does the actual reading from the smb server.
+ *
+ * The cache code is almost directly taken from ncpfs
+ */
 static int 
 smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *dir = dentry->d_inode;
-	struct cache_head *cachep;
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	union  smb_dir_cache *cache = NULL;
+	struct smb_cache_control ctl;
+	struct page *page = NULL;
 	int result;
 
+	ctl.page  = NULL;
+	ctl.cache = NULL;
+
 	VERBOSE("reading %s/%s, f_pos=%d\n",
 		DENTRY_PATH(dentry),  (int) filp->f_pos);
 
 	result = 0;
-	switch ((unsigned int) filp->f_pos)
-	{
+	switch ((unsigned int) filp->f_pos) {
 	case 0:
 		if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
 			goto out;
 		filp->f_pos = 1;
+		/* fallthrough */
 	case 1:
 		if (filldir(dirent, "..", 2, 1,
-				dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+			    dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
 			goto out;
 		filp->f_pos = 2;
 	}
@@ -83,61 +93,119 @@
 	result = smb_revalidate_inode(dentry);
 	if (result)
 		goto out;
-	/*
-	 * Get the cache pointer ...
-	 */
-	result = -EIO;
-	cachep = smb_get_dircache(dentry);
-	if (!cachep)
-		goto out;
 
-	/*
-	 * Make sure the cache is up-to-date.
-	 *
-	 * To detect changes on the server we refill on each "new" access.
-	 *
-	 * Directory mtime would be nice to use for finding changes,
-	 * unfortunately some servers (NT4) doesn't update on local changes.
-	 */
-	if (!cachep->valid || filp->f_pos == 2)
-	{
-		result = smb_refill_dircache(cachep, dentry);
-		if (result)
-			goto out_free;
-	}
 
-	result = 0;
-
-	while (1)
-	{
-		struct cache_dirent this_dirent, *entry = &this_dirent;
+	page = grab_cache_page(&dir->i_data, 0);
+	if (!page)
+		goto read_really;
+
+	ctl.cache = cache = kmap(page);
+	ctl.head  = cache->head;
+
+	if (!Page_Uptodate(page) || !ctl.head.eof) {
+		VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
+			 DENTRY_PATH(dentry), Page_Uptodate(page),ctl.head.eof);
+		goto init_cache;
+	}
+
+	if (filp->f_pos == 2) {
+		if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
+			goto init_cache;
 
-		if (!smb_find_in_cache(cachep, filp->f_pos, entry))
-			break;
 		/*
-		 * Check whether to look up the inode number.
+		 * N.B. ncpfs checks mtime of dentry too here, we don't.
+		 *   1. common smb servers do not update mtime on dir changes
+		 *   2. it requires an extra smb request
+		 *      (revalidate has the same timeout as ctl.head.time)
+		 *
+		 * Instead smbfs invalidates its own cache on local changes
+		 * and remote changes are not seen until timeout.
 		 */
-		if (!entry->ino) {
-			struct qstr qname;
-			/* N.B. Make cache_dirent name a qstr! */
-			qname.name = entry->name;
-			qname.len  = entry->len;
-			entry->ino = find_inode_number(dentry, &qname);
-			if (!entry->ino)
-				entry->ino = iunique(dentry->d_sb, 2);
-		}
-
-		if (filldir(dirent, entry->name, entry->len, 
-				    filp->f_pos, entry->ino, DT_UNKNOWN) < 0)
-			break;
-		filp->f_pos += 1;
 	}
 
-	/*
-	 * Release the dircache.
-	 */
-out_free:
-	smb_free_dircache(cachep);
+	if (filp->f_pos > ctl.head.end)
+		goto finished;
+
+	ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
+	ctl.ofs  = ctl.fpos / SMB_DIRCACHE_SIZE;
+	ctl.idx  = ctl.fpos % SMB_DIRCACHE_SIZE;
+
+	for (;;) {
+		if (ctl.ofs != 0) {
+			ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
+			if (!ctl.page)
+				goto invalid_cache;
+			ctl.cache = kmap(ctl.page);
+			if (!Page_Uptodate(ctl.page))
+				goto invalid_cache;
+		}
+		while (ctl.idx < SMB_DIRCACHE_SIZE) {
+			struct dentry *dent;
+			int res;
+
+			dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
+					     dentry, filp->f_pos);
+			if (!dent)
+				goto invalid_cache;
+
+			res = filldir(dirent, dent->d_name.name,
+				      dent->d_name.len, filp->f_pos,
+				      dent->d_inode->i_ino, DT_UNKNOWN);
+			dput(dent);
+			if (res)
+				goto finished;
+			filp->f_pos += 1;
+			ctl.idx += 1;
+			if (filp->f_pos > ctl.head.end)
+				goto finished;
+		}
+		if (ctl.page) {
+			kunmap(ctl.page);
+			SetPageUptodate(ctl.page);
+			UnlockPage(ctl.page);
+			page_cache_release(ctl.page);
+			ctl.page = NULL;
+		}
+		ctl.idx  = 0;
+		ctl.ofs += 1;
+	}
+invalid_cache:
+	if (ctl.page) {
+		kunmap(ctl.page);
+		UnlockPage(ctl.page);
+		page_cache_release(ctl.page);
+		ctl.page = NULL;
+	}
+	ctl.cache = cache;
+init_cache:
+	smb_invalidate_dircache_entries(dentry);
+	ctl.head.time = jiffies;
+	ctl.head.eof = 0;
+	ctl.fpos = 2;
+	ctl.ofs = 0;
+	ctl.idx = SMB_DIRCACHE_START;
+	ctl.filled = 0;
+	ctl.valid  = 1;
+read_really:
+	result = smb_proc_readdir(filp, dirent, filldir, &ctl);
+	if (ctl.idx == -1)
+		goto invalid_cache;	/* retry */
+	ctl.head.end = ctl.fpos - 1;
+	ctl.head.eof = ctl.valid;
+finished:
+	if (page) {
+		cache->head = ctl.head;
+		kunmap(page);
+		SetPageUptodate(page);
+		UnlockPage(page);
+		page_cache_release(page);
+	}
+	if (ctl.page) {
+		kunmap(ctl.page);
+		SetPageUptodate(ctl.page);
+		UnlockPage(ctl.page);
+		page_cache_release(ctl.page);
+	}
 out:
 	return result;
 }
@@ -204,16 +272,17 @@
 static int
 smb_lookup_validate(struct dentry * dentry, int flags)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	struct inode * inode = dentry->d_inode;
 	unsigned long age = jiffies - dentry->d_time;
 	int valid;
 
 	/*
 	 * The default validation is based on dentry age:
-	 * we believe in dentries for 5 seconds.  (But each
+	 * we believe in dentries for a few seconds.  (But each
 	 * successful server lookup renews the timestamp.)
 	 */
-	valid = (age <= SMBFS_MAX_AGE);
+	valid = (age <= SMB_MAX_AGE(server));
 #ifdef SMBFS_DEBUG_VERBOSE
 	if (!valid)
 		VERBOSE("%s/%s not valid, age=%lu\n", 
@@ -286,6 +355,22 @@
 }
 
 /*
+ * Initialize a new dentry
+ */
+void
+smb_new_dentry(struct dentry *dentry)
+{
+	struct smb_sb_info *server = server_from_dentry(dentry);
+
+	if (server->mnt->flags & SMB_MOUNT_CASE)
+		dentry->d_op = &smbfs_dentry_operations_case;
+	else
+		dentry->d_op = &smbfs_dentry_operations;
+	dentry->d_time = jiffies;
+}
+
+
+/*
  * Whenever a lookup succeeds, we know the parent directories
  * are all valid, so we want to update the dentry timestamps.
  * N.B. Move this to dcache?
@@ -441,6 +526,7 @@
 	if (!d_unhashed(dentry))
 		goto out;
 
+	smb_invalid_dir_cache(dir);
 	error = smb_proc_rmdir(dentry);
 
 out:
@@ -457,6 +543,7 @@
 	 */
 	smb_close(dentry->d_inode);
 
+	smb_invalid_dir_cache(dir);
 	error = smb_proc_unlink(dentry);
 	if (!error)
 		smb_renew_times(dentry);
diff -urN linux-2.4.2-pre4/fs/smbfs/file.c linux/fs/smbfs/file.c
--- linux-2.4.2-pre4/fs/smbfs/file.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/smbfs/file.c	Mon Dec  3 22:29:17 2001
@@ -38,7 +38,7 @@
 static int
 smb_readpage_sync(struct dentry *dentry, struct page *page)
 {
-	char *buffer = page_address(page);
+	char *buffer = kmap(page);
 	unsigned long offset = page->index << PAGE_CACHE_SHIFT;
 	int rsize = smb_get_rsize(server_from_dentry(dentry));
 	int count = PAGE_SIZE;
@@ -76,6 +76,7 @@
 	result = 0;
 
 io_error:
+	kunmap(page);
 	UnlockPage(page);
 	return result;
 }
@@ -89,8 +90,6 @@
 	int		error;
 	struct dentry  *dentry = file->f_dentry;
 
-	DEBUG1("readpage %p\n", page_address(page));
-
 	get_page(page);
 	error = smb_readpage_sync(dentry, page);
 	put_page(page);
@@ -105,7 +104,7 @@
 smb_writepage_sync(struct inode *inode, struct page *page,
 		   unsigned long offset, unsigned int count)
 {
-	u8 *buffer = page_address(page) + offset;
+	char *buffer = kmap(page) + offset;
 	int wsize = smb_get_wsize(server_from_inode(inode));
 	int result, written = 0;
 
@@ -139,8 +138,10 @@
 		inode->i_mtime = inode->i_atime = CURRENT_TIME;
 		if (offset > inode->i_size)
 			inode->i_size = offset;
-		inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE;
+		inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
 	} while (count);
+
+	kunmap(page);
 	return written ? written : result;
 }
 
diff -urN linux-2.4.2-pre4/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- linux-2.4.2-pre4/fs/smbfs/inode.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/smbfs/inode.c	Mon Dec  3 22:29:17 2001
@@ -43,7 +43,6 @@
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
 static int  smb_statfs(struct super_block *, struct statfs *);
-static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
 
 static struct super_operations smb_sops =
 {
@@ -110,7 +109,7 @@
 		fattr->attr |= aRONLY;
 }
 
-static void
+void
 smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
 {
 	inode->i_mode	= fattr->f_mode;
@@ -125,8 +124,7 @@
 	 * Don't change the size and mtime/atime fields
 	 * if we're writing to the file.
 	 */
-	if (!(inode->u.smbfs_i.cache_valid & SMB_F_LOCALWRITE))
-	{
+	if (!(inode->u.smbfs_i.flags & SMB_F_LOCALWRITE)) {
 		inode->i_size  = fattr->f_size;
 		inode->i_mtime = fattr->f_mtime;
 		inode->i_atime = fattr->f_atime;
@@ -211,6 +209,7 @@
 int
 smb_revalidate_inode(struct dentry *dentry)
 {
+	struct smb_sb_info *s = server_from_dentry(dentry);
 	struct inode *inode = dentry->d_inode;
 	time_t last_time;
 	int error = 0;
@@ -221,8 +220,7 @@
 	 * the inode will be up-to-date.
 	 */
 	lock_kernel();
-	if (S_ISREG(inode->i_mode) && smb_is_open(inode))
-	{
+	if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
 		if (inode->u.smbfs_i.access != SMB_O_RDONLY)
 			goto out;
 	}
@@ -230,10 +228,9 @@
 	/*
 	 * Check whether we've recently refreshed the inode.
 	 */
-	if (time_before(jiffies, inode->u.smbfs_i.oldmtime + HZ/10))
-	{
-		VERBOSE("up-to-date, jiffies=%lu, oldtime=%lu\n",
-			jiffies, inode->u.smbfs_i.oldmtime);
+	if (time_before(jiffies, inode->u.smbfs_i.oldmtime + SMB_MAX_AGE(s))) {
+		VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
+			inode->i_ino, jiffies, inode->u.smbfs_i.oldmtime);
 		goto out;
 	}
 
@@ -243,16 +240,13 @@
 	 */
 	last_time = inode->i_mtime;
 	error = smb_refresh_inode(dentry);
-	if (error || inode->i_mtime != last_time)
-	{
+	if (error || inode->i_mtime != last_time) {
 		VERBOSE("%s/%s changed, old=%ld, new=%ld\n",
 			DENTRY_PATH(dentry),
 			(long) last_time, (long) inode->i_mtime);
 
 		if (!S_ISDIR(inode->i_mode))
 			invalidate_inode_pages(inode);
-		else
-			smb_invalid_dir_cache(inode);
 	}
 out:
 	unlock_kernel();
@@ -287,6 +281,7 @@
 	{ "dir_mode",	1, 0, 'd' },
 	{ "iocharset",	1, 0, 'i' },
 	{ "codepage",	1, 0, 'c' },
+	{ "ttl",	1, 0, 't' },
 	{ NULL,		0, 0, 0}
 };
 
@@ -339,6 +334,9 @@
 			strncpy(mnt->codepage.remote_name, optarg,
 				SMB_NLS_MAXNAMELEN);
 			break;
+		case 't':
+			mnt->ttl = value;
+			break;
 		default:
 			printk ("smbfs: Unrecognized mount option %s\n",
 				optopt);
@@ -437,6 +435,7 @@
 	strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
 		SMB_NLS_MAXNAMELEN);
 
+	mnt->ttl = 1000;
 	if (ver == SMB_MOUNT_OLDVERSION) {
 		mnt->version = oldmnt->version;
 
@@ -483,6 +482,7 @@
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
 		goto out_no_root;
+	smb_new_dentry(sb->s_root);
 
 	return sb;
 
diff -urN linux-2.4.2-pre4/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- linux-2.4.2-pre4/fs/smbfs/proc.c	Mon Dec  3 22:29:07 2001
+++ linux/fs/smbfs/proc.c	Mon Dec  3 22:29:17 2001
@@ -78,6 +78,7 @@
 	}
 }
 
+#if 0
 static void
 str_lower(char *name, int len)
 {
@@ -88,6 +89,7 @@
 		name++;
 	}
 }
+#endif
 
 /* reverse a string inline. This is used by the dircache walking routines */
 static void reverse_string(char *buf, int len)
@@ -358,6 +360,72 @@
 	*date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
 }
 
+/* The following are taken from fs/ntfs/util.c */
+
+/*
+ * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
+ * into Unix UTC (based 1970-01-01, in seconds).
+ *
+ * This is very gross because
+ * 1: We must do 64-bit division on a 32-bit machine
+ * 2: We can't use libgcc for long long operations in the kernel
+ * 3: Floating point math in the kernel would corrupt user data
+ */
+static time_t
+smb_ntutc2unixutc(struct smb_sb_info *server, u64 ntutc)
+{
+	const unsigned int D = 10000000;
+	unsigned int H = (unsigned int)(ntutc >> 32);
+	unsigned int L = (unsigned int)ntutc;
+	unsigned int numerator2;
+	unsigned int lowseconds;
+	unsigned int result;
+
+	/*
+	 * It is best to subtract 0x019db1ded53e8000 first.
+	 * Then the 1601-based date becomes a 1970-based date.
+	 */
+	if (L < (unsigned)0xd53e8000) H--;
+	L -= (unsigned)0xd53e8000;
+	H -= (unsigned)0x019db1de;
+
+	/*
+	 * Now divide 64-bit numbers on a 32-bit machine :-)
+	 * With the subtraction already done, the result fits in 32 bits.
+	 * The numerator fits in 56 bits and the denominator fits
+	 * in 24 bits, so we can shift by 8 bits to make this work.
+	 */
+
+	numerator2  = (H<<8) | (L>>24);
+	result      = (numerator2 / D);   /* shifted 24 right!! */
+	lowseconds  = result << 24;
+
+	numerator2  = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
+	result      = (numerator2 / D);   /* shifted 16 right!! */
+	lowseconds |= result << 16;
+
+	numerator2  = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
+	result      = (numerator2 / D);   /* shifted 8 right!! */
+	lowseconds |= result << 8;
+
+	numerator2  = ((numerator2-result*D)<<8) | (L&0xff);
+	result      = (numerator2 / D);   /* not shifted */
+	lowseconds |= result;
+
+	return lowseconds;
+}
+
+#if 0
+/* Convert the Unix UTC into NT time */
+static u64
+smb_unixutc2ntutc(struct smb_sb_info *server, time_t t)
+{
+	/* Note: timezone conversion is probably wrong. */
+	return ((utc2local(server, t) + (u64)(369*365+89)*24*3600) * 10000000);
+}
+#endif
+
+
 /*****************************************************************************/
 /*                                                                           */
 /*  Support section.                                                         */
@@ -421,22 +489,16 @@
 }
 
 /*
- * Returns the maximum read or write size for the current packet size
- * and max_xmit value.
+ * Returns the maximum read or write size for the "payload". Making all of the
+ * packet fit within the negotiated max_xmit size.
+ *
  * N.B. Since this value is usually computed before locking the server,
  * the server's packet size must never be decreased!
  */
-static int
+static inline int
 smb_get_xmitsize(struct smb_sb_info *server, int overhead)
 {
-	int size = server->packet_size;
-
-	/*
-	 * Start with the smaller of packet size and max_xmit ...
-	 */
-	if (size > server->opt.max_xmit)
-		size = server->opt.max_xmit;
-	return size - overhead;
+	return server->opt.max_xmit - overhead;
 }
 
 /*
@@ -783,6 +845,23 @@
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
 		server->opt.capabilities);
 
+	/* Make sure we can fit a message of the negotiated size in our
+	   packet buffer. */
+	if (server->opt.max_xmit > server->packet_size) {
+		int len = smb_round_length(server->opt.max_xmit);
+		char *buf = smb_vmalloc(len);
+		if (buf) {
+			server->packet = buf;
+			server->packet_size = len;
+		} else {
+			/* else continue with the too small buffer? */
+			PARANOIA("Failed to allocate new packet buffer: "
+				 "max_xmit=%d, packet_size=%d\n",
+				 server->opt.max_xmit, server->packet_size);
+			server->opt.max_xmit = server->packet_size;
+		}
+	}
+
 out:
 #ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
@@ -1025,7 +1104,7 @@
 
 		result = smb_proc_close(server, ino->u.smbfs_i.fileid,
 						ino->i_mtime);
-		ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
+		ino->u.smbfs_i.flags &= ~SMB_F_LOCALWRITE;
 		/*
 		 * Force a revalidation after closing ... some servers
 		 * don't post the size until the file has been closed.
@@ -1115,7 +1194,7 @@
 
 out:
 	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
-		inode->ino, inode->u.smbfs_i.fileid, count, result);
+		inode->i_ino, inode->u.smbfs_i.fileid, count, result);
 	smb_unlock_server(server);
 	return result;
 }
@@ -1128,7 +1207,7 @@
 	__u8 *p;
 	
 	VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
-		inode->ino, inode->u.smbfs_i.fileid, count, offset,
+		inode->i_ino, inode->u.smbfs_i.fileid, count, offset,
 		server->packet_size);
 
 	smb_lock_server(server);
@@ -1355,14 +1434,13 @@
 	smb_lock_server(server);
 
       retry:
-	p = smb_setup_header(server, SMBwrite, 5, 0);
+	p = smb_setup_header(server, SMBwrite, 5, 3);
 	WSET(server->packet, smb_vwv0, fid);
 	WSET(server->packet, smb_vwv1, 0);
 	DSET(server->packet, smb_vwv2, length);
 	WSET(server->packet, smb_vwv4, 0);
-	*p++ = 4;
-	*p++ = 0;
-	smb_setup_bcc(server, p);
+	*p++ = 1;
+	WSET(p, 0, 0);
 
 	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
 		if (smb_retry(server))
@@ -1419,38 +1497,47 @@
 }
 
 /*
- * Note that we are now returning the name as a reference to avoid
- * an extra copy, and that the upper/lower casing is done in place.
+ * Decode a dirent for old protocols
+ *
+ * qname is filled with the decoded, and possibly translated, name.
+ * fattr receives decoded attributes
  *
  * Bugs Noted:
  * (1) Pathworks servers may pad the name with extra spaces.
  */
-static __u8 *
-smb_decode_dirent(struct smb_sb_info *server, __u8 *p, 
-			struct cache_dirent *entry)
+static char *
+smb_decode_short_dirent(struct smb_sb_info *server, char *p,
+			struct qstr *qname, struct smb_fattr *fattr)
 {
 	int len;
 
 	/*
 	 * SMB doesn't have a concept of inode numbers ...
 	 */
-	entry->ino = 0;
+	smb_init_dirent(server, fattr);
+	fattr->f_ino = 0;	/* FIXME: do we need this? */
 
 	p += SMB_STATUS_SIZE;	/* reserved (search_status) */
-	entry->name = p + 9;
-	len = strlen(entry->name);
-	if (len > 12)
-		len = 12;
+	fattr->attr = *p;
+	fattr->f_mtime = date_dos2unix(server, WVAL(p, 3), WVAL(p, 1));
+	fattr->f_size = DVAL(p, 5);
+	fattr->f_ctime = fattr->f_mtime;
+	fattr->f_atime = fattr->f_mtime;
+	qname->name = p + 9;
+	len = strnlen(qname->name, 12);
 
 	/*
 	 * Trim trailing blanks for Pathworks servers
 	 */
-	while (len > 2 && entry->name[len-1] == ' ')
+	while (len > 2 && qname->name[len-1] == ' ')
 		len--;
-	entry->len = len;
+	qname->len = len;
+
+	smb_finish_dirent(server, fattr);
 
+#if 0
 	/* FIXME: These only work for ascii chars, and recent smbmount doesn't
-	   allow the flag to be set anyway. Remove? */
+	   allow the flag to be set anyway. It kills const. Remove? */
 	switch (server->opt.case_handling) {
 	case SMB_CASE_UPPER:
 		str_upper(entry->name, len);
@@ -1461,24 +1548,31 @@
 	default:
 		break;
 	}
+#endif
 
-	entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     entry->name, len,
+	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+				     qname->name, len,
 				     server->remote_nls, server->local_nls);
-	entry->name = server->name_buf;
+	qname->name = server->name_buf;
 
-	DEBUG1("len=%d, name=%.*s\n", entry->len, entry->len, entry->name);
+	DEBUG1("len=%d, name=%.*s\n", qname->len, qname->len, qname->name);
 	return p + 22;
 }
 
-/* This routine is used to read in directory entries from the network.
-   Note that it is for short directory name seeks, i.e.: protocol <
-   SMB_PROTOCOL_LANMAN2 */
-
+/*
+ * This routine is used to read in directory entries from the network.
+ * Note that it is for short directory name seeks, i.e.: protocol <
+ * SMB_PROTOCOL_LANMAN2
+ */
 static int
-smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
-		       void *cachep)
+smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
+		       struct smb_cache_control *ctl)
 {
+	struct dentry *dir = filp->f_dentry;
+	struct smb_sb_info *server = server_from_dentry(dir);
+	struct qstr qname;
+	struct smb_fattr fattr;
+
 	unsigned char *p;
 	int result;
 	int i, first, entries_seen, entries;
@@ -1489,13 +1583,10 @@
 	static struct qstr mask = { "*.*", 3, 0 };
 	unsigned char *last_status;
 
-	VERBOSE("%s/%s, pos=%d\n", DENTRY_PATH(dir), fpos);
+	VERBOSE("%s/%s\n", DENTRY_PATH(dir));
 
 	smb_lock_server(server);
 
-	/* N.B. We need to reinitialize the cache to restart */
-retry:
-	smb_init_dircache(cachep);
 	first = 1;
 	entries = 0;
 	entries_seen = 2; /* implicit . and .. */
@@ -1530,8 +1621,10 @@
 			if ((server->rcls == ERRDOS) && 
 			    (server->err  == ERRnofiles))
 				break;
-			if (smb_retry(server))
-				goto retry;
+			if (smb_retry(server)) {
+				ctl->idx = -1;	/* retry */
+				result = 0;
+			}
 			goto unlock_return;
 		}
 		p = SMB_VWV(server->packet);
@@ -1568,23 +1661,18 @@
 		/* Now we are ready to parse smb directory entries. */
 
 		for (i = 0; i < count; i++) {
-			struct cache_dirent this_ent, *entry = &this_ent;
+			p = smb_decode_short_dirent(server, p, 
+						    &qname, &fattr);
 
-			p = smb_decode_dirent(server, p, entry);
-			if (entries_seen == 2 && entry->name[0] == '.') {
-				if (entry->len == 1)
+			if (entries_seen == 2 && qname.name[0] == '.') {
+				if (qname.len == 1)
 					continue;
-				if (entry->name[1] == '.' && entry->len == 2)
+				if (qname.name[1] == '.' && qname.len == 2)
 					continue;
 			}
-			if (entries_seen >= fpos) {
-				DEBUG1("fpos=%u\n", entries_seen);
-				smb_add_to_cache(cachep, entry, entries_seen);
-				entries++;
-			} else {
-				VERBOSE("skipped, seen=%d, i=%d, fpos=%d\n",
-					entries_seen, i, fpos);
-			}
+			if (!smb_fill_cache(filp, dirent, filldir, ctl, 
+					    &qname, &fattr))
+				;	/* stop reading? */
 			entries_seen++;
 		}
 	}
@@ -1600,44 +1688,69 @@
  *   level 1 for anything below NT1 protocol
  *   level 260 for NT1 protocol
  *
- * We return a reference to the name string to avoid copying, and perform
- * any needed upper/lower casing in place.
+ * qname is filled with the decoded, and possibly translated, name
+ * fattr receives decoded attributes.
  *
  * Bugs Noted:
  * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
  */
 static char *
-smb_decode_long_dirent(struct smb_sb_info *server, char *p,
-			struct cache_dirent *entry, int level)
+smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
+		       struct qstr *qname, struct smb_fattr *fattr)
 {
 	char *result;
 	unsigned int len = 0;
+	__u16 date, time;
 
 	/*
 	 * SMB doesn't have a concept of inode numbers ...
 	 */
-	entry->ino = 0;
+	smb_init_dirent(server, fattr);
+	fattr->f_ino = 0;	/* FIXME: do we need this? */
 
 	switch (level) {
 	case 1:
 		len = *((unsigned char *) p + 22);
-		entry->name = p + 23;
+		qname->name = p + 23;
 		result = p + 24 + len;
 
+		date = WVAL(p, 0);
+		time = WVAL(p, 2);
+		fattr->f_ctime = date_dos2unix(server, date, time);
+
+		date = WVAL(p, 4);
+		time = WVAL(p, 6);
+		fattr->f_atime = date_dos2unix(server, date, time);
+
+		date = WVAL(p, 8);
+		time = WVAL(p, 10);
+		fattr->f_mtime = date_dos2unix(server, date, time);
+		fattr->f_size = DVAL(p, 12);
+		/* ULONG allocation size */
+		fattr->attr = WVAL(p, 20);
+
 		VERBOSE("info 1 at %p, len=%d, name=%.*s\n",
-			p, len, len, entry->name);
+			p, len, len, qname->name);
 		break;
 	case 260:
 		result = p + WVAL(p, 0);
 		len = DVAL(p, 60);
 		if (len > 255) len = 255;
 		/* NT4 null terminates */
-		entry->name = p + 94;
-		if (len && entry->name[len-1] == '\0')
+		qname->name = p + 94;
+		if (len && qname->name[len-1] == '\0')
 			len--;
 
+		fattr->f_ctime = smb_ntutc2unixutc(server, LVAL(p, 8));
+		fattr->f_atime = smb_ntutc2unixutc(server, LVAL(p, 16));
+		fattr->f_mtime = smb_ntutc2unixutc(server, LVAL(p, 24));
+		/* change time (32) */
+		fattr->f_size = DVAL(p, 40);
+		/* alloc size (48) */
+		fattr->attr = DVAL(p, 56);
+
 		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
-			p, len, len, entry->name);
+			p, len, len, qname->name);
 		break;
 	default:
 		PARANOIA("Unknown info level %d\n", level);
@@ -1645,21 +1758,28 @@
 		goto out;
 	}
 
+	smb_finish_dirent(server, fattr);
+
+#if 0
+	/* FIXME: These only work for ascii chars, and recent smbmount doesn't
+	   allow the flag to be set anyway. Remove? */
 	switch (server->opt.case_handling) {
 	case SMB_CASE_UPPER:
-		str_upper(entry->name, len);
+		str_upper(qname->name, len);
 		break;
 	case SMB_CASE_LOWER:
-		str_lower(entry->name, len);
+		str_lower(qname->name, len);
 		break;
 	default:
 		break;
 	}
+#endif
 
-	entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     entry->name, len,
+	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+				     qname->name, len,
 				     server->remote_nls, server->local_nls);
-	entry->name = server->name_buf;
+	qname->name = server->name_buf;
+
 out:
 	return result;
 }
@@ -1682,13 +1802,18 @@
  * single file. (E.g. echo hi >foo breaks, rm -f foo works.)
  */
 static int
-smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
-		      void *cachep)
+smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
+		      struct smb_cache_control *ctl)
 {
-	unsigned char *p;
-	char *mask, *lastname, *param = server->temp_buf;
+	struct dentry *dir = filp->f_dentry;
+	struct smb_sb_info *server = server_from_dentry(dir);
+	struct qstr qname;
+	struct smb_fattr fattr;
+
+	unsigned char *p, *lastname;
+	char *mask, *param = server->temp_buf;
 	__u16 command;
-	int first, entries, entries_seen;
+	int first, entries_seen;
 
 	/* Both NT and OS/2 accept info level 1 (but see note below). */
 	int info_level = 260;
@@ -1714,7 +1839,6 @@
 
 	smb_lock_server(server);
 
-retry:
 	/*
 	 * Encode the initial path
 	 */
@@ -1722,17 +1846,13 @@
 
 	mask_len = smb_encode_path(server, mask, dir, &star);
 	if (mask_len < 0) {
-		entries = mask_len;
+		result = mask_len;
 		goto unlock_return;
 	}
 	first = 1;
-	VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask);
+	VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask);
 
-	/*
-	 * We must reinitialize the dircache when retrying.
-	 */
-	smb_init_dircache(cachep);
-	entries = 0;
+	result = 0;
 	entries_seen = 2;
 	ff_eos = 0;
 
@@ -1741,7 +1861,7 @@
 		if (loop_count > 10) {
 			printk(KERN_WARNING "smb_proc_readdir_long: "
 			       "Looping in FIND_NEXT??\n");
-			entries = -EIO;
+			result = -EIO;
 			break;
 		}
 
@@ -1773,10 +1893,11 @@
 		if (result < 0) {
 			if (smb_retry(server)) {
 				PARANOIA("error=%d, retrying\n", result);
-				goto retry;
+				ctl->idx = -1;	/* retry */
+				result = 0;
+				goto unlock_return;
 			}
 			PARANOIA("error=%d, breaking\n", result);
-			entries = result;
 			break;
 		}
 
@@ -1788,10 +1909,10 @@
 			continue;
                 }
 
-		if (server->rcls != 0) { 
-			PARANOIA("name=%s, entries=%d, rcls=%d, err=%d\n",
-				 mask, entries, server->rcls, server->err);
-			entries = -smb_errno(server);
+		if (server->rcls != 0) {
+			result = -smb_errno(server);
+			PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",
+				 mask, result, server->rcls, server->err);
 			break;
 		}
 
@@ -1810,41 +1931,44 @@
 		if (ff_searchcount == 0)
 			break;
 
-		/* we might need the lastname for continuations */
+		/*
+		 * We might need the lastname for continuations.
+		 *
+		 * Note that some servers (win95?) point to the filename and
+		 * others (NT4, Samba using NT1) to the dir entry. We assume
+		 * here that those who do not point to a filename do not need
+		 * this info to continue the listing. OS/2 needs this, but it
+		 * talks "infolevel 1"
+		 */
 		mask_len = 0;
-		if (ff_lastname > 0) {
+		if (info_level == 1 && ff_lastname > 0 &&
+		    ff_lastname < resp_data_len) {
 			lastname = resp_data + ff_lastname;
-			switch (info_level) {
-			case 260:
-				if (ff_lastname < resp_data_len)
-					mask_len = resp_data_len - ff_lastname;
-				break;
-			case 1:
-				/* Win NT 4.0 doesn't set the length byte */
-				lastname++;
-				if (ff_lastname + 2 < resp_data_len)
-					mask_len = strlen(lastname);
-				break;
-			}
+
+			/* lastname points to a length byte */
+			mask_len = *lastname++;
+			if (ff_lastname + 1 + mask_len > resp_data_len)
+				mask_len = resp_data_len-ff_lastname-1;
+
 			/*
 			 * Update the mask string for the next message.
 			 */
+			if (mask_len < 0)
+				mask_len = 0;
 			if (mask_len > 255)
 				mask_len = 255;
 			if (mask_len)
 				strncpy(mask, lastname, mask_len);
 		}
-		mask[mask_len] = 0;
-		VERBOSE("new mask, len=%d@%d, mask=%s\n",
-			mask_len, ff_lastname, mask);
+		mask_len = strnlen(mask, mask_len);
+		VERBOSE("new mask, len=%d@%d of %d, mask=%.*s\n",
+			mask_len, ff_lastname, resp_data_len, mask_len, mask);
 
 		/* Now we are ready to parse smb directory entries. */
 
 		/* point to the data bytes */
 		p = resp_data;
 		for (i = 0; i < ff_searchcount; i++) {
-			struct cache_dirent this_ent, *entry = &this_ent;
-
 			/* make sure we stay within the buffer */
 			if (p >= resp_data + resp_data_len) {
 				printk(KERN_ERR "smb_proc_readdir_long: "
@@ -1856,21 +1980,21 @@
 				goto unlock_return;
 			}
 
-			p = smb_decode_long_dirent(server, p, entry,
-							info_level);
+			p = smb_decode_long_dirent(server, p, info_level,
+						   &qname, &fattr);
 
 			/* ignore . and .. from the server */
-			if (entries_seen == 2 && entry->name[0] == '.') {
-				if (entry->len == 1)
+			if (entries_seen == 2 && qname.name[0] == '.') {
+				if (qname.len == 1)
 					continue;
-				if (entry->name[1] == '.' && entry->len == 2)
+				if (qname.name[1] == '.' && qname.len == 2)
 					continue;
 			}
-			if (entries_seen >= fpos) {
-				smb_add_to_cache(cachep, entry, entries_seen);
-				entries += 1;
-			}
- 			entries_seen++;
+
+			if (!smb_fill_cache(filp, dirent, filldir, ctl, 
+					    &qname, &fattr))
+				;	/* stop reading? */
+			entries_seen++;
 		}
 
 		VERBOSE("received %d entries, eos=%d\n", ff_searchcount,ff_eos);
@@ -1881,19 +2005,19 @@
 
 unlock_return:
 	smb_unlock_server(server);
-	return entries;
+	return result;
 }
 
 int
-smb_proc_readdir(struct dentry *dir, int fpos, void *cachep)
+smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
+		 struct smb_cache_control *ctl)
 {
-	struct smb_sb_info *server;
+	struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
 
-	server = server_from_dentry(dir);
 	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
-		return smb_proc_readdir_long(server, dir, fpos, cachep);
+		return smb_proc_readdir_long(filp, dirent, filldir, ctl);
 	else
-		return smb_proc_readdir_short(server, dir, fpos, cachep);
+		return smb_proc_readdir_short(filp, dirent, filldir, ctl);
 }
 
 /*
diff -urN linux-2.4.2-pre4/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- linux-2.4.2-pre4/fs/smbfs/sock.c	Mon Dec 11 12:39:45 2000
+++ linux/fs/smbfs/sock.c	Mon Dec  3 22:29:17 2001
@@ -109,7 +109,7 @@
 	struct data_callback* job=ptr;
 	struct socket *socket = job->sk->socket;
 	unsigned char peek_buf[4];
-	int result;
+	int result = 0;
 	mm_segment_t fs;
 	int count = 100;   /* this is a lot, we should have some data waiting */
 	int found = 0;
@@ -477,14 +477,12 @@
 	unsigned int total_p = 0, total_d = 0, buf_len = 0;
 	int result;
 
-	while (1)
-	{
+	while (1) {
 		result = smb_receive(server);
 		if (result < 0)
 			goto out;
 		inbuf = server->packet;
-		if (server->rcls != 0)
-		{
+		if (server->rcls != 0) {
 			*parm = *data = inbuf;
 			*ldata = *lparm = 0;
 			goto out;
@@ -508,13 +506,11 @@
 		parm_len += parm_count;
 		data_len += data_count;
 
-		if (!rcv_buf)
-		{
+		if (!rcv_buf) {
 			/*
 			 * Check for fast track processing ... just this packet.
 			 */
-			if (parm_count == parm_tot && data_count == data_tot)
-			{
+			if (parm_count == parm_tot && data_count == data_tot) {
 				VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n",
 					parm_disp, parm_offset, parm_count,
 					data_disp, data_offset, data_count);
@@ -523,10 +519,6 @@
 				goto success;
 			}
 
-			if (parm_tot > TRANS2_MAX_TRANSFER ||
-	  		    data_tot > TRANS2_MAX_TRANSFER)
-				goto out_too_long;
-
 			/*
 			 * Save the total parameter and data length.
 			 */
@@ -537,14 +529,15 @@
 			if (server->packet_size > buf_len)
 				buf_len = server->packet_size;
 			buf_len = smb_round_length(buf_len);
+			if (buf_len > SMB_MAX_PACKET_SIZE)
+				goto out_too_long;
 
 			rcv_buf = smb_vmalloc(buf_len);
 			if (!rcv_buf)
 				goto out_no_mem;
 			*parm = rcv_buf;
 			*data = rcv_buf + total_p;
-		}
-		else if (data_tot > total_d || parm_tot > total_p)
+		} else if (data_tot > total_d || parm_tot > total_p)
 			goto out_data_grew;
 
 		if (parm_disp + parm_count > total_p)
@@ -571,8 +564,7 @@
 	 * old one, in which case we just copy the data.
 	 */
 	inbuf = server->packet;
-	if (buf_len >= server->packet_size)
-	{
+	if (buf_len >= server->packet_size) {
 		server->packet_size = buf_len;
 		server->packet = rcv_buf;
 		rcv_buf = inbuf;
@@ -716,6 +708,7 @@
 	struct socket *sock = server_sock(server);
 	struct scm_cookie scm;
 	int err;
+	int mparam, mdata;
 
 	/* I know the following is very ugly, but I want to build the
 	   smb packet as efficiently as possible. */
@@ -737,19 +730,30 @@
 	struct iovec iov[4];
 	struct msghdr msg;
 
-	/* N.B. This test isn't valid! packet_size may be < max_xmit */
+	/* FIXME! this test needs to include SMB overhead too, I think ... */
 	if ((bcc + oparam) > server->opt.max_xmit)
-	{
 		return -ENOMEM;
-	}
 	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
 
+	/*
+	 * max parameters + max data + max setup == max_xmit to make NT4 happy
+	 * and not abort the transfer or split into multiple responses.
+	 *
+	 * -100 is to make room for headers, which OS/2 seems to include in the
+	 * size calculation while NT4 does not?
+	 */
+	mparam = SMB_TRANS2_MAX_PARAM;
+	mdata = server->opt.max_xmit - mparam - 100;
+	if (mdata < 1024) {
+		mdata = 1024;
+		mparam = 20;
+	}
+
 	WSET(server->packet, smb_tpscnt, lparam);
 	WSET(server->packet, smb_tdscnt, ldata);
-	/* N.B. these values should reflect out current packet size */
-	WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
-	WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
-	WSET(server->packet, smb_msrcnt, 0);
+	WSET(server->packet, smb_mprcnt, mparam);
+	WSET(server->packet, smb_mdrcnt, mdata);
+	WSET(server->packet, smb_msrcnt, 0);    /* max setup always 0 ? */
 	WSET(server->packet, smb_flags, 0);
 	DSET(server->packet, smb_timeout, 0);
 	WSET(server->packet, smb_pscnt, lparam);
@@ -781,8 +785,7 @@
 	iov[3].iov_len = ldata;
 
 	err = scm_send(sock, &msg, &scm);
-        if (err >= 0)
-	{
+        if (err >= 0) {
 		err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);
 		scm_destroy(&scm);
 	}
diff -urN linux-2.4.2-pre4/include/asm-sparc/highmem.h linux/include/asm-sparc/highmem.h
--- linux-2.4.2-pre4/include/asm-sparc/highmem.h	Wed Nov  8 19:01:34 2000
+++ linux/include/asm-sparc/highmem.h	Mon Dec  3 22:29:17 2001
@@ -2,7 +2,7 @@
  * highmem.h: virtual kernel memory mappings for high memory
  *
  * Used in CONFIG_HIGHMEM systems for memory pages which
- * are not addressable by direct kernel virtual adresses.
+ * are not addressable by direct kernel virtual addresses.
  *
  * Copyright (C) 1999 Gerhard Wichert, Siemens AG
  *		      Gerhard.Wichert@pdb.siemens.de
diff -urN linux-2.4.2-pre4/include/linux/dcache.h linux/include/linux/dcache.h
--- linux-2.4.2-pre4/include/linux/dcache.h	Mon Dec  3 22:29:07 2001
+++ linux/include/linux/dcache.h	Mon Dec  3 22:29:17 2001
@@ -37,20 +37,18 @@
 extern struct dentry_stat_t dentry_stat;
 
 /* Name hashing routines. Initial hash value */
+/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
 #define init_name_hash()		0
 
 /* partial hash update function. Assume roughly 4 bits per character */
 static __inline__ unsigned long partial_name_hash(unsigned long c, unsigned long prevhash)
 {
-	prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
-	return prevhash ^ c;
+	return (prevhash + (c << 4) + (c >> 4)) * 11;
 }
 
 /* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */
 static __inline__ unsigned long end_name_hash(unsigned long hash)
 {
-	if (sizeof(hash) > sizeof(unsigned int))
-		hash += hash >> 4*sizeof(hash);
 	return (unsigned int) hash;
 }
 
diff -urN linux-2.4.2-pre4/include/linux/kdev_t.h linux/include/linux/kdev_t.h
--- linux-2.4.2-pre4/include/linux/kdev_t.h	Mon Jan 24 11:04:37 2000
+++ linux/include/linux/kdev_t.h	Mon Dec  3 22:29:17 2001
@@ -1,6 +1,6 @@
 #ifndef _LINUX_KDEV_T_H
 #define _LINUX_KDEV_T_H
-#ifdef __KERNEL__
+#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
 /*
 As a preparation for the introduction of larger device numbers,
 we introduce a type kdev_t to hold them. No information about
@@ -101,7 +101,7 @@
 	return MKDEV(major, minor);
 }
 
-#else /* __KERNEL__ */
+#else /* __KERNEL__ || _LVM_H_INCLUDE */
 
 /*
 Some programs want their definitions of MAJOR and MINOR and MKDEV
@@ -110,5 +110,5 @@
 #define MAJOR(dev)	((dev)>>8)
 #define MINOR(dev)	((dev) & 0xff)
 #define MKDEV(ma,mi)	((ma)<<8 | (mi))
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ || _LVM_H_INCLUDE */
 #endif
diff -urN linux-2.4.2-pre4/include/linux/list.h linux/include/linux/list.h
--- linux-2.4.2-pre4/include/linux/list.h	Tue Aug  8 12:18:58 2000
+++ linux/include/linux/list.h	Mon Dec  3 22:29:17 2001
@@ -1,7 +1,7 @@
 #ifndef _LINUX_LIST_H
 #define _LINUX_LIST_H
 
-#ifdef __KERNEL__
+#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
 
 /*
  * Simple doubly linked list implementation.
@@ -149,6 +149,6 @@
 #define list_for_each(pos, head) \
 	for (pos = (head)->next; pos != (head); pos = pos->next)
 
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
 #endif
diff -urN linux-2.4.2-pre4/include/linux/lvm.h linux/include/linux/lvm.h
--- linux-2.4.2-pre4/include/linux/lvm.h	Mon Jan 29 16:19:41 2001
+++ linux/include/linux/lvm.h	Mon Dec  3 22:29:17 2001
@@ -95,15 +95,8 @@
  */
 #endif				/* #ifdef __KERNEL__ */
 
-#ifndef __KERNEL__
-#define __KERNEL__
 #include <linux/kdev_t.h>
 #include <linux/list.h>
-#undef __KERNEL__
-#else
-#include <linux/kdev_t.h>
-#include <linux/list.h>
-#endif				/* #ifndef __KERNEL__ */
 
 #include <asm/types.h>
 #include <linux/major.h>
diff -urN linux-2.4.2-pre4/include/linux/mm.h linux/include/linux/mm.h
--- linux-2.4.2-pre4/include/linux/mm.h	Mon Jan 29 23:24:56 2001
+++ linux/include/linux/mm.h	Mon Dec  3 22:29:17 2001
@@ -200,8 +200,8 @@
 					smp_mb__before_clear_bit(); \
 					if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
 					smp_mb__after_clear_bit(); \
-					if (waitqueue_active(&page->wait)) \
-						wake_up(&page->wait); \
+					if (waitqueue_active(&(page)->wait)) \
+						wake_up(&(page)->wait); \
 				} while (0)
 #define PageError(page)		test_bit(PG_error, &(page)->flags)
 #define SetPageError(page)	set_bit(PG_error, &(page)->flags)
diff -urN linux-2.4.2-pre4/include/linux/smb.h linux/include/linux/smb.h
--- linux-2.4.2-pre4/include/linux/smb.h	Mon Jan 29 23:24:55 2001
+++ linux/include/linux/smb.h	Mon Dec  3 22:29:17 2001
@@ -93,14 +93,6 @@
 	unsigned long	f_blocks;
 };
 
-struct smb_dirent {
-	struct smb_fattr attr;
-
-	int f_pos;
-	int len;
-	__u8 name[SMB_MAXNAMELEN];
-};
-
 enum smb_conn_state {
         CONN_VALID,             /* everything's fine */
         CONN_INVALID,           /* Something went wrong, but did not
@@ -120,11 +112,13 @@
 
 #define SMB_HEADER_LEN   37     /* includes everything up to, but not
                                  * including smb_bcc */
-#define SMB_DEF_MAX_XMIT 32768
-#define SMB_INITIAL_PACKET_SIZE 4000
 
-/* Allocate max. 1 page */
-#define TRANS2_MAX_TRANSFER (4096-17)
+#define SMB_INITIAL_PACKET_SIZE		4000
+#define SMB_MAX_PACKET_SIZE		32768
+
+/* reserve this much space for trans2 parameters. Shouldn't have to be more
+   than 10 or so, but OS/2 seems happier like this. */
+#define SMB_TRANS2_MAX_PARAM 64
 
 #endif
 #endif
diff -urN linux-2.4.2-pre4/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- linux-2.4.2-pre4/include/linux/smb_fs.h	Mon Dec 11 13:26:20 2000
+++ linux/include/linux/smb_fs.h	Mon Dec  3 22:29:17 2001
@@ -20,23 +20,31 @@
 /* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */
 #define	SMB_IOC_GETMOUNTUID32		_IOR('u', 3, __kernel_uid32_t)
 
+
 #ifdef __KERNEL__
 
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/smb_mount.h>
 #include <asm/unaligned.h>
 
+
+/* macro names are short for word, double-word, long value (?) */
 #define WVAL(buf,pos) \
-(le16_to_cpu(get_unaligned((__u16 *)((__u8 *)(buf) + (pos)))))
+	(le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos)))))
 #define DVAL(buf,pos) \
-(le32_to_cpu(get_unaligned((__u32 *)((__u8 *)(buf) + (pos)))))
+	(le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos)))))
+#define LVAL(buf,pos) \
+	(le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos)))))
 #define WSET(buf,pos,val) \
-put_unaligned(cpu_to_le16((__u16)(val)), (__u16 *)((__u8 *)(buf) + (pos)))
+	put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos)))
 #define DSET(buf,pos,val) \
-put_unaligned(cpu_to_le32((__u32)(val)), (__u32 *)((__u8 *)(buf) + (pos)))
+	put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos)))
+#define LSET(buf,pos,val) \
+	put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos)))
 
 /* where to find the base of the SMB packet proper */
-#define smb_base(buf) ((__u8 *)(((__u8 *)(buf))+4))
-
-#include <linux/vmalloc.h>
+#define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
 
 #ifdef DEBUG_SMB_MALLOC
 
@@ -70,7 +78,6 @@
 /*
  * Flags for the in-memory inode
  */
-#define SMB_F_CACHEVALID	0x01	/* directory cache valid */
 #define SMB_F_LOCALWRITE	0x02	/* file modified locally */
 
 
@@ -89,8 +96,54 @@
 #define SMB_CAP_LARGE_READX      0x4000
 
 
-/* linux/fs/smbfs/mmap.c */
-int smb_mmap(struct file *, struct vm_area_struct *);
+/*
+ * This is the time we allow an inode, dentry or dir cache to live. It is bad
+ * for performance to have shorter ttl on an inode than on the cache. It can
+ * cause refresh on each inode for a dir listing ... one-by-one
+ */
+#define SMB_MAX_AGE(server) (((server)->mnt->ttl * HZ) / 1000)
+
+static inline void
+smb_age_dentry(struct smb_sb_info *server, struct dentry *dentry)
+{
+	dentry->d_time = jiffies - SMB_MAX_AGE(server);
+}
+
+struct smb_cache_head {
+	time_t		mtime;	/* unused */
+	unsigned long	time;	/* cache age */
+	unsigned long	end;	/* last valid fpos in cache */
+	int		eof;
+};
+
+#define SMB_DIRCACHE_SIZE	((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *)))
+union smb_dir_cache {
+	struct smb_cache_head   head;
+	struct dentry           *dentry[SMB_DIRCACHE_SIZE];
+};
+
+#define SMB_FIRSTCACHE_SIZE	((int)((SMB_DIRCACHE_SIZE * \
+	sizeof(struct dentry *) - sizeof(struct smb_cache_head)) / \
+	sizeof(struct dentry *)))
+
+#define SMB_DIRCACHE_START      (SMB_DIRCACHE_SIZE - SMB_FIRSTCACHE_SIZE)
+
+struct smb_cache_control {
+	struct  smb_cache_head		head;
+	struct  page			*page;
+	union   smb_dir_cache		*cache;
+	unsigned long			fpos, ofs;
+	int				filled, valid, idx;
+};
+
+static inline int
+smb_is_open(struct inode *i)
+{
+	return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
+}
+
+
+/* FIXME! the prototype list is probably not correct. Automate? */
 
 /* linux/fs/smbfs/file.c */
 extern struct inode_operations smb_file_inode_operations;
@@ -100,6 +153,7 @@
 /* linux/fs/smbfs/dir.c */
 extern struct inode_operations smb_dir_inode_operations;
 extern struct file_operations smb_dir_operations;
+void smb_new_dentry(struct dentry *dentry);
 void smb_renew_times(struct dentry *);
 
 /* linux/fs/smbfs/ioctl.c */
@@ -108,16 +162,15 @@
 /* linux/fs/smbfs/inode.c */
 struct super_block *smb_read_super(struct super_block *, void *, int);
 void smb_get_inode_attr(struct inode *, struct smb_fattr *);
+void smb_set_inode_attr(struct inode *, struct smb_fattr *);
 void smb_invalidate_inodes(struct smb_sb_info *);
 int  smb_revalidate_inode(struct dentry *);
 int  smb_notify_change(struct dentry *, struct iattr *);
-unsigned long smb_invent_inos(unsigned long);
 struct inode *smb_iget(struct super_block *, struct smb_fattr *);
 
 /* linux/fs/smbfs/proc.c */
 int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
 __u32 smb_len(unsigned char *);
-__u8 *smb_encode_smb_length(__u8 *, __u32);
 __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
 int smb_get_rsize(struct smb_sb_info *);
 int smb_get_wsize(struct smb_sb_info *);
@@ -133,32 +186,21 @@
 int smb_proc_mkdir(struct dentry *);
 int smb_proc_rmdir(struct dentry *);
 int smb_proc_unlink(struct dentry *);
-int smb_proc_readdir(struct dentry *, int, void *);
+int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
+		     struct smb_cache_control *ctl);
 int smb_proc_getattr(struct dentry *, struct smb_fattr *);
 int smb_proc_setattr(struct dentry *, struct smb_fattr *);
 int smb_proc_settime(struct dentry *, struct smb_fattr *);
 int smb_proc_dskattr(struct super_block *, struct statfs *);
-int smb_proc_reconnect(struct smb_sb_info *);
-int smb_proc_connect(struct smb_sb_info *);
 int smb_proc_disconnect(struct smb_sb_info *);
 int smb_proc_trunc(struct smb_sb_info *, __u16, __u32);
 void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *);
 
-static inline int
-smb_is_open(struct inode *i)
-{
-	return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
-}
-
 /* linux/fs/smbfs/sock.c */
 int smb_round_length(int);
 int smb_valid_socket(struct inode *);
 void smb_close_socket(struct smb_sb_info *);
-int smb_release(struct smb_sb_info *server);
-int smb_connect(struct smb_sb_info *server);
 int smb_request(struct smb_sb_info *server);
-int smb_request_read_raw(struct smb_sb_info *, unsigned char *, int);
-int smb_request_write_raw(struct smb_sb_info *, unsigned const char *, int);
 int smb_catch_keepalive(struct smb_sb_info *server);
 int smb_dont_catch_keepalive(struct smb_sb_info *server);
 int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
@@ -169,69 +211,14 @@
 
 /* fs/smbfs/cache.c */
 
-/*
- * The cache index describes the pages mapped starting
- * at offset PAGE_SIZE.  We keep only a minimal amount
- * of information here.
- */
-struct cache_index {
-	unsigned short num_entries;
-	unsigned short space;
-	struct cache_block * block;
-};
-
-#define NINDEX (PAGE_SIZE-64)/sizeof(struct cache_index)
-/*
- * The cache head is mapped as the page at offset 0.
- */
-struct cache_head {
-	int	valid;
-	int	status;		/* error code or 0 */
-	int	entries;	/* total entries */
-	int	pages;		/* number of data pages */
-	int	idx;		/* index of current data page */
-	struct cache_index index[NINDEX];
-};
-
-/*
- * An array of cache_entry structures holds information
- * for each object in the cache_block.
- */
-struct cache_entry {
-	ino_t ino;
-	unsigned short namelen;
-	unsigned short offset;
-};
-
-/*
- * The cache blocks hold the actual data.  The entry table grows up
- * while the names grow down, and we have space until they meet.
- */
-struct cache_block {
-	union {
-		struct cache_entry table[1];
-		char	names[PAGE_SIZE];
-	} cb_data;
-};
-
-/*
- * To return an entry, we can pass a reference to the
- * name instead of having to copy it.
- */
-struct cache_dirent {
-	ino_t ino;
-	unsigned long pos;
-	int len;
-	char * name;
-};
+void smb_invalid_dir_cache(struct inode * dir);
+void smb_invalidate_dircache_entries(struct dentry *parent);
+struct dentry * smb_dget_fpos(struct dentry *dentry, struct dentry *parent, 
+			      unsigned long fpos);
+int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+		   struct smb_cache_control *ctrl, struct qstr *qname,
+		   struct smb_fattr *entry);
 
-struct cache_head * smb_get_dircache(struct dentry *);
-void smb_init_dircache(struct cache_head *);
-void smb_free_dircache(struct cache_head *);
-int  smb_refill_dircache(struct cache_head *, struct dentry *);
-void smb_add_to_cache(struct cache_head *, struct cache_dirent *, off_t);
-int  smb_find_in_cache(struct cache_head *, off_t, struct cache_dirent *);
-void smb_invalid_dir_cache(struct inode *);
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.2-pre4/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h
--- linux-2.4.2-pre4/include/linux/smb_fs_i.h	Mon Jan 29 23:24:55 2001
+++ linux/include/linux/smb_fs_i.h	Mon Dec  3 22:29:17 2001
@@ -26,7 +26,7 @@
 	__u16 attr;		/* Attribute fields, DOS value */
 
 	__u16 access;		/* Access mode */
-	__u16 cache_valid;	/* dircache valid? */
+	__u16 flags;		/* status flags */
 	unsigned long oldmtime;	/* last time refreshed */
 	unsigned long closed;	/* timestamp when closed */
 	unsigned openers;	/* number of fileid users */
diff -urN linux-2.4.2-pre4/include/linux/smb_mount.h linux/include/linux/smb_mount.h
--- linux-2.4.2-pre4/include/linux/smb_mount.h	Mon Dec 11 13:26:20 2000
+++ linux/include/linux/smb_mount.h	Mon Dec  3 22:29:17 2001
@@ -50,6 +50,9 @@
 
 	u32 flags;
 
+        /* maximum age in jiffies (inode, dentry and dircache) */
+	int ttl;
+
 	struct smb_nls_codepage codepage;
 };
 
diff -urN linux-2.4.2-pre4/include/math-emu/op-2.h linux/include/math-emu/op-2.h
--- linux-2.4.2-pre4/include/math-emu/op-2.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/op-2.h	Mon Dec  3 22:29:17 2001
@@ -79,7 +79,7 @@
     else								\
       {									\
 	X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |			\
-		  (((X##_f1 << (sz - (N))) | X##_f0) != 0));		\
+		(((X##_f1 << (2*_FP_W_TYPE_SIZE - (N))) | X##_f0) != 0)); \
 	X##_f1 = 0;							\
       }									\
   } while (0)
diff -urN linux-2.4.2-pre4/include/net/scm.h linux/include/net/scm.h
--- linux-2.4.2-pre4/include/net/scm.h	Tue Oct 27 09:57:19 1998
+++ linux/include/net/scm.h	Mon Dec  3 22:29:17 2001
@@ -63,5 +63,5 @@
 }
 
 
-#endif __LINUX_NET_SCM_H
+#endif /* __LINUX_NET_SCM_H */
 
diff -urN linux-2.4.2-pre4/include/pcmcia/bulkmem.h linux/include/pcmcia/bulkmem.h
--- linux-2.4.2-pre4/include/pcmcia/bulkmem.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/bulkmem.h	Mon Dec  3 22:29:17 2001
@@ -18,7 +18,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/bus_ops.h linux/include/pcmcia/bus_ops.h
--- linux-2.4.2-pre4/include/pcmcia/bus_ops.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/bus_ops.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h
--- linux-2.4.2-pre4/include/pcmcia/ciscode.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/ciscode.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/cisreg.h linux/include/pcmcia/cisreg.h
--- linux-2.4.2-pre4/include/pcmcia/cisreg.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/cisreg.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/cistpl.h linux/include/pcmcia/cistpl.h
--- linux-2.4.2-pre4/include/pcmcia/cistpl.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/cistpl.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/cs.h linux/include/pcmcia/cs.h
--- linux-2.4.2-pre4/include/pcmcia/cs.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/cs.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h
--- linux-2.4.2-pre4/include/pcmcia/cs_types.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/cs_types.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/driver_ops.h linux/include/pcmcia/driver_ops.h
--- linux-2.4.2-pre4/include/pcmcia/driver_ops.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/driver_ops.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-2.4.2-pre4/include/pcmcia/ds.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/ds.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/ftl.h linux/include/pcmcia/ftl.h
--- linux-2.4.2-pre4/include/pcmcia/ftl.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/ftl.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/mem_op.h linux/include/pcmcia/mem_op.h
--- linux-2.4.2-pre4/include/pcmcia/mem_op.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/mem_op.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/memory.h linux/include/pcmcia/memory.h
--- linux-2.4.2-pre4/include/pcmcia/memory.h	Sat Sep  2 00:13:49 2000
+++ linux/include/pcmcia/memory.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- linux-2.4.2-pre4/include/pcmcia/ss.h	Fri Sep 15 16:31:09 2000
+++ linux/include/pcmcia/ss.h	Mon Dec  3 22:29:17 2001
@@ -16,7 +16,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), in which
+ * terms of the GNU General Public License version 2 (the "GPL"), in which
  * case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
diff -urN linux-2.4.2-pre4/ipc/msg.c linux/ipc/msg.c
--- linux-2.4.2-pre4/ipc/msg.c	Mon Dec  3 22:29:07 2001
+++ linux/ipc/msg.c	Mon Dec  3 22:29:17 2001
@@ -473,7 +473,7 @@
 		int success_return;
 		if (!buf)
 			return -EFAULT;
-		if(cmd == MSG_STAT && msqid > msg_ids.size)
+		if(cmd == MSG_STAT && msqid >= msg_ids.size)
 			return -EINVAL;
 
 		memset(&tbuf,0,sizeof(tbuf));
diff -urN linux-2.4.2-pre4/ipc/sem.c linux/ipc/sem.c
--- linux-2.4.2-pre4/ipc/sem.c	Mon Dec  3 22:29:07 2001
+++ linux/ipc/sem.c	Mon Dec  3 22:29:17 2001
@@ -467,7 +467,7 @@
 		struct semid64_ds tbuf;
 		int id;
 
-		if(semid > sem_ids.size)
+		if(semid >= sem_ids.size)
 			return -EINVAL;
 
 		memset(&tbuf,0,sizeof(tbuf));
@@ -922,7 +922,7 @@
 
 		tmp = sem_lock(semid);
 		if(tmp==NULL) {
-			if(queue.status != -EIDRM)
+			if(queue.prev != NULL)
 				BUG();
 			current->semsleeping = NULL;
 			error = -EIDRM;
diff -urN linux-2.4.2-pre4/ipc/util.c linux/ipc/util.c
--- linux-2.4.2-pre4/ipc/util.c	Mon Dec  3 22:29:07 2001
+++ linux/ipc/util.c	Mon Dec  3 22:29:17 2001
@@ -185,7 +185,7 @@
 {
 	struct kern_ipc_perm* p;
 	int lid = id % SEQ_MULTIPLIER;
-	if(lid > ids->size)
+	if(lid >= ids->size)
 		BUG();
 	p = ids->entries[lid].p;
 	ids->entries[lid].p = NULL;
diff -urN linux-2.4.2-pre4/ipc/util.h linux/ipc/util.h
--- linux-2.4.2-pre4/ipc/util.h	Thu Jun 22 07:09:45 2000
+++ linux/ipc/util.h	Mon Dec  3 22:29:17 2001
@@ -54,7 +54,7 @@
 {
 	struct kern_ipc_perm* out;
 	int lid = id % SEQ_MULTIPLIER;
-	if(lid > ids->size)
+	if(lid >= ids->size)
 		return NULL;
 
 	out = ids->entries[lid].p;
@@ -69,7 +69,7 @@
 {
 	struct kern_ipc_perm* out;
 	int lid = id % SEQ_MULTIPLIER;
-	if(lid > ids->size)
+	if(lid >= ids->size)
 		return NULL;
 
 	spin_lock(&ids->ary);
diff -urN linux-2.4.2-pre4/kernel/module.c linux/kernel/module.c
--- linux-2.4.2-pre4/kernel/module.c	Mon Nov 27 17:38:07 2000
+++ linux/kernel/module.c	Mon Dec  3 22:29:17 2001
@@ -23,6 +23,7 @@
  * Fix sys_init_module race, Andrew Morton <andrewm@uow.edu.au> Oct 2000
  *     http://www.uwsg.iu.edu/hypermail/linux/kernel/0008.3/0379.html
  * Replace xxx_module_symbol with inter_module_xxx.  Keith Owens <kaos@ocs.com.au> Oct 2000
+ * Add a module list lock for kernel fault race fixing. Alan Cox <alan@redhat.com>
  *
  * This source is covered by the GNU GPL, the same as all kernel sources.
  */
@@ -65,6 +66,17 @@
 static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
 static int kmalloc_failed;
 
+/*
+ *	This lock prevents modifications that might race the kernel fault
+ *	fixups. It does not prevent reader walks that the modules code
+ *	does. The kernel lock does that.
+ *
+ *	Since vmalloc fault fixups occur in any context this lock is taken
+ *	irqsave at all times.
+ */
+ 
+spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED;
+
 /**
  * inter_module_register - register a new set of inter module data.
  * @im_name: an arbitrary string to identify the data, must be unique
@@ -283,6 +295,7 @@
 	char *name;
 	long namelen, error;
 	struct module *mod;
+	unsigned long flags;
 
 	if (!capable(CAP_SYS_MODULE))
 		return -EPERM;
@@ -306,14 +319,16 @@
 
 	memset(mod, 0, sizeof(*mod));
 	mod->size_of_struct = sizeof(*mod);
-	mod->next = module_list;
 	mod->name = (char *)(mod + 1);
 	mod->size = size;
 	memcpy((char*)(mod+1), name, namelen+1);
 
 	put_mod_name(name);
 
+	spin_lock_irqsave(&modlist_lock, flags);
+	mod->next = module_list;
 	module_list = mod;	/* link it in */
+	spin_unlock_irqrestore(&modlist_lock, flags);
 
 	error = (long) mod;
 	goto err0;
@@ -628,6 +643,7 @@
 	/* Do automatic reaping */
 restart:
 	something_changed = 0;
+	
 	for (mod = module_list; mod != &kernel_module; mod = next) {
 		next = mod->next;
 		spin_lock(&unload_lock);
@@ -651,10 +667,13 @@
 			spin_unlock(&unload_lock);
 		}
 	}
+	
 	if (something_changed)
 		goto restart;
+		
 	for (mod = module_list; mod != &kernel_module; mod = mod->next)
 		mod->flags &= ~MOD_JUST_FREED;
+	
 	error = 0;
 out:
 	unlock_kernel();
@@ -1018,6 +1037,7 @@
 {
 	struct module_ref *dep;
 	unsigned i;
+	unsigned long flags;
 
 	/* Let the module clean up.  */
 
@@ -1041,6 +1061,7 @@
 
 	/* And from the main module list.  */
 
+	spin_lock_irqsave(&modlist_lock, flags);
 	if (mod == module_list) {
 		module_list = mod->next;
 	} else {
@@ -1049,6 +1070,7 @@
 			continue;
 		p->next = mod->next;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
 
 	/* And free the memory.  */
 
diff -urN linux-2.4.2-pre4/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.4.2-pre4/kernel/sysctl.c	Mon Dec  3 22:29:07 2001
+++ linux/kernel/sysctl.c	Mon Dec  3 22:29:17 2001
@@ -75,6 +75,14 @@
 extern char reboot_command [];
 extern int stop_a_enabled;
 #endif
+
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+extern int sysctl_ieee_emulation_warnings;
+#endif
+extern int sysctl_userprocess_debug;
+#endif
+
 #ifdef __powerpc__
 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
@@ -233,6 +241,14 @@
 	{KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
 	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
 	 &minolduid, &maxolduid},
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+	{KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
+	 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
+#endif
+	{KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
+	 &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
+#endif
 	{0}
 };
 
@@ -320,8 +336,6 @@
 
 	if (nlen <= 0 || nlen >= CTL_MAXNAME)
 		return -ENOTDIR;
-	if ((int) newlen < 0)
-		return -EINVAL;
 	if (oldval) {
 		int old_len;
 		if (!oldlenp || get_user(old_len, oldlenp))
@@ -425,7 +439,8 @@
 			void *oldval, size_t *oldlenp,
 			void *newval, size_t newlen, void **context)
 {
-	int op = 0, rc, len;
+	int op = 0, rc;
+	size_t len;
 
 	if (oldval)
 		op |= 004;
@@ -468,13 +483,82 @@
 	return 0;
 }
 
+/**
+ * register_sysctl_table - register a sysctl heirarchy
+ * @table: the top-level table structure
+ * @insert_at_head: whether the entry should be inserted in front or at the end
+ *
+ * Register a sysctl table heirarchy. @table should be a filled in ctl_table
+ * array. An entry with a ctl_name of 0 terminates the table. 
+ *
+ * The members of the &ctl_table structure are used as follows:
+ *
+ * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
+ *            must be unique within that level of sysctl
+ *
+ * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
+ *            enter a sysctl file
+ *
+ * data - a pointer to data for use by proc_handler
+ *
+ * maxlen - the maximum size in bytes of the data
+ *
+ * mode - the file permissions for the /proc/sys file, and for sysctl(2)
+ *
+ * child - a pointer to the child sysctl table if this entry is a directory, or
+ *         %NULL.
+ *
+ * proc_handler - the text handler routine (described below)
+ *
+ * strategy - the strategy routine (described below)
+ *
+ * de - for internal use by the sysctl routines
+ *
+ * extra1, extra2 - extra pointers usable by the proc handler routines
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories.
+ *
+ * sysctl(2) can automatically manage read and write requests through
+ * the sysctl table.  The data and maxlen fields of the ctl_table
+ * struct enable minimal validation of the values being written to be
+ * performed, and the mode field allows minimal authentication.
+ *
+ * More sophisticated management can be enabled by the provision of a
+ * strategy routine with the table entry.  This will be called before
+ * any automatic read or write of the data is performed.
+ *
+ * The strategy routine may return
+ *
+ * < 0 - Error occurred (error is passed to user process)
+ *
+ * 0   - OK - proceed with automatic read or write.
+ *
+ * > 0 - OK - read or write has been done by the strategy routine, so
+ *       return immediately.
+ *
+ * There must be a proc_handler routine for any terminal nodes
+ * mirrored under /proc/sys (non-terminals are handled by a built-in
+ * directory handler).  Several default handlers are available to
+ * cover common cases -
+ *
+ * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
+ * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
+ * proc_doulongvec_minmax()
+ *
+ * It is the handler's job to read the input buffer from user memory
+ * and process it. The handler should return 0 on success.
+ *
+ * This routine returns %NULL on a failure to register, and a pointer
+ * to the table header on success.
+ */
 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
 					       int insert_at_head)
 {
 	struct ctl_table_header *tmp;
 	tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
 	if (!tmp)
-		return 0;
+		return NULL;
 	tmp->ctl_table = table;
 	INIT_LIST_HEAD(&tmp->ctl_entry);
 	if (insert_at_head)
@@ -487,8 +571,12 @@
 	return tmp;
 }
 
-/*
- * Unlink and free a ctl_table.
+/**
+ * unregister_sysctl_table - unregister a sysctl table heirarchy
+ * @header: the header returned from register_sysctl_table
+ *
+ * Unregisters the sysctl table and all children. proc entries may not
+ * actually be removed until they are no longer used by anyone.
  */
 void unregister_sysctl_table(struct ctl_table_header * header)
 {
@@ -632,10 +720,27 @@
 	return test_perm(inode->i_mode, op);
 }
 
+/**
+ * proc_dostring - read a string sysctl
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes a string from/to the user buffer. If the kernel
+ * buffer provided is not large enough to hold the string, the
+ * string is truncated. The copied string is %NULL-terminated.
+ * If the string is being read by the user process, it is copied
+ * and a newline '\n' is added. It is truncated if the buffer is
+ * not large enough.
+ *
+ * Returns 0 on success.
+ */
 int proc_dostring(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
-	int len;
+	size_t len;
 	char *p, c;
 	
 	if (!table->data || !table->maxlen || !*lenp ||
@@ -711,7 +816,9 @@
 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp, int conv, int op)
 {
-	int *i, vleft, first=1, len, left, neg, val;
+	int *i, vleft, first=1, neg, val;
+	size_t left, len;
+	
 	#define TMPBUFLEN 20
 	char buf[TMPBUFLEN], *p;
 	
@@ -809,6 +916,19 @@
 	return 0;
 }
 
+/**
+ * proc_dointvec - read a vector of integers
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string. 
+ *
+ * Returns 0 on success.
+ */
 int proc_dointvec(ctl_table *table, int write, struct file *filp,
 		     void *buffer, size_t *lenp)
 {
@@ -829,10 +949,27 @@
 				(current->pid == 1) ? OP_SET : OP_AND);
 }
 
+/**
+ * proc_dointvec_minmax - read a vector of integers with min/max values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * This routine will ensure the values are within the range specified by
+ * table->extra1 (min) and table->extra2 (max).
+ *
+ * Returns 0 on success.
+ */
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
-	int *i, *min, *max, vleft, first=1, len, left, neg, val;
+	int *i, *min, *max, vleft, first=1, neg, val;
+	size_t len, left;
 	#define TMPBUFLEN 20
 	char buf[TMPBUFLEN], *p;
 	
@@ -927,10 +1064,6 @@
 	return 0;
 }
 
-/*
- * an unsigned long function version
- */
-
 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
 				     struct file *filp,
 				     void *buffer, size_t *lenp,
@@ -939,7 +1072,8 @@
 {
 #define TMPBUFLEN 20
 	unsigned long *i, *min, *max, val;
-	int vleft, first=1, len, left, neg;
+	int vleft, first=1, neg;
+	size_t len, left;
 	char buf[TMPBUFLEN], *p;
 	
 	if (!table->data || !table->maxlen || !*lenp ||
@@ -1036,12 +1170,45 @@
 #undef TMPBUFLEN
 }
 
+/**
+ * proc_doulongvec_minmax - read a vector of long integers with min/max values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * This routine will ensure the values are within the range specified by
+ * table->extra1 (min) and table->extra2 (max).
+ *
+ * Returns 0 on success.
+ */
 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
 			   void *buffer, size_t *lenp)
 {
     return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
 }
 
+/**
+ * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
+ * values from/to the user buffer, treated as an ASCII string. The values
+ * are treated as milliseconds, and converted to jiffies when they are stored.
+ *
+ * This routine will ensure the values are within the range specified by
+ * table->extra1 (min) and table->extra2 (max).
+ *
+ * Returns 0 on success.
+ */
 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
 				      struct file *filp,
 				      void *buffer, size_t *lenp)
@@ -1051,7 +1218,21 @@
 }
 
 
-/* Like proc_dointvec, but converts seconds to jiffies */
+/**
+ * proc_dointvec_jiffies - read a vector of integers as seconds
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string. 
+ * The values read are assumed to be in seconds, and are converted into
+ * jiffies.
+ *
+ * Returns 0 on success.
+ */
 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 			  void *buffer, size_t *lenp)
 {
@@ -1122,7 +1303,7 @@
 		  void *oldval, size_t *oldlenp,
 		  void *newval, size_t newlen, void **context)
 {
-	int l, len;
+	size_t l, len;
 	
 	if (!table->data || !table->maxlen) 
 		return -ENOTDIR;
@@ -1165,7 +1346,8 @@
 		void *oldval, size_t *oldlenp,
 		void *newval, size_t newlen, void **context)
 {
-	int i, length, *vec, *min, *max;
+	int i, *vec, *min, *max;
+	size_t length;
 
 	if (newval && newlen) {
 		if (newlen % sizeof(int) != 0)
diff -urN linux-2.4.2-pre4/mm/filemap.c linux/mm/filemap.c
--- linux-2.4.2-pre4/mm/filemap.c	Mon Dec  3 22:29:07 2001
+++ linux/mm/filemap.c	Mon Dec  3 22:29:17 2001
@@ -19,7 +19,6 @@
 #include <linux/blkdev.h>
 #include <linux/file.h>
 #include <linux/swapctl.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 
diff -urN linux-2.4.2-pre4/net/core/skbuff.c linux/net/core/skbuff.c
--- linux-2.4.2-pre4/net/core/skbuff.c	Mon Dec  3 22:29:07 2001
+++ linux/net/core/skbuff.c	Mon Dec  3 22:29:17 2001
@@ -48,7 +48,6 @@
 #include <linux/netdevice.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
-#include <linux/slab.h>
 #include <linux/cache.h>
 #include <linux/init.h>
 
diff -urN linux-2.4.2-pre4/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- linux-2.4.2-pre4/net/ipx/af_ipx.c	Mon Dec  3 22:29:07 2001
+++ linux/net/ipx/af_ipx.c	Mon Dec  3 22:29:17 2001
@@ -1194,6 +1194,7 @@
 		atomic_set(&intrfc->refcnt, 1);
 		MOD_INC_USE_COUNT;
 		ipxitf_insert(intrfc);
+		dev_hold(dev);
 	}
 
 	return intrfc;
@@ -1835,6 +1836,10 @@
 		return -EFAULT;
 
 	len = min(len, sizeof(int));
+	
+	if(len < 0)
+		return -EINVAL;
+		
 	if (put_user(len, optlen))
 		return -EFAULT;
 
