## Automatically generated incremental diff
## From:   linux-2.4.18-pre7
## To:     linux-2.4.18-pre8
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.4.18-pre7/CREDITS linux/CREDITS
--- linux-2.4.18-pre7/CREDITS	Mon Feb  4 12:55:36 2002
+++ linux/CREDITS	Mon Feb  4 12:55:41 2002
@@ -1213,10 +1213,10 @@
 S: Germany
 
 N: Christoph Hellwig
-E: hch@caldera.de
 E: hch@infradead.org
 D: misc driver & makefile hacking
 D: freevxfs driver
+D: sysvfs maintainer
 S: Triftstraße 26
 S: 38644 Goslar
 S: Germany
diff -urN linux-2.4.18-pre7/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.18-pre7/Documentation/Configure.help	Mon Feb  4 12:55:36 2002
+++ linux/Documentation/Configure.help	Mon Feb  4 12:55:42 2002
@@ -15226,7 +15226,7 @@
   Currently, the valid values are:
   big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861,
   cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936,
-  cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1,
+  cp949, cp950, cp1250, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1,
   iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7,
   iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15,
   koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8.
@@ -15465,6 +15465,16 @@
   only, not to the file contents. You can include several codepages;
   say Y here if you want to include the DOS codepage for Traditional
   Chinese(Big5).
+
+Central European (Codepage 1250)
+CONFIG_NLS_CODEPAGE_1250
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Windows CP-1250
+  character set, which works for most Latin-written Slavic and Central
+  European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
+  Slovak, Slovene.
 
 NLS ISO 8859-1 (Latin 1; Western European Languages)
 CONFIG_NLS_ISO8859_1
diff -urN linux-2.4.18-pre7/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt
--- linux-2.4.18-pre7/Documentation/kbuild/config-language.txt	Fri Aug  4 18:38:44 2000
+++ linux/Documentation/kbuild/config-language.txt	Mon Feb  4 12:55:42 2002
@@ -30,7 +30,7 @@
     scripts/Configure   make config, make oldconfig
     scripts/Menuconfig  make menuconfig
     scripts/tkparse     make xconfig
-    mconfig             (in development)
+    mconfig             ftp.kernel.org/pub/linux/kernel/people/hch/mconfig/
 
 'Configure' is a bash script which interprets Config.in files by sourcing
 them.  Some of the Config Language commands are native bash commands;
@@ -52,9 +52,6 @@
 into an internal syntax tree and then hands the syntax tree to one of
 several user-interface front ends.
 
-This document describes the behaviour of all four interpreters, even though
-mconfig has not been released at the time of writing.
-
 
 
 === Statements
@@ -489,7 +486,7 @@
 Configure:  implemented
 Menuconfig: implemented
 XConfig:    implemented
-mconfig:    not implemented
+mconfig:    implemented
 
 Example:
 
diff -urN linux-2.4.18-pre7/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- linux-2.4.18-pre7/Documentation/scsi-generic.txt	Tue May  1 16:04:56 2001
+++ linux/Documentation/scsi-generic.txt	Mon Feb  4 12:55:43 2002
@@ -1,793 +1,101 @@
-            Notes on Linux's SG driver version 2.1.39
-            -----------------------------------------
-                                                        20010329
-
+            Notes on Linux SCSI Generic (sg) driver
+            ---------------------------------------
+                                                        20020126
 Introduction
 ============
 The SCSI Generic driver (sg) is one of the four "high level" SCSI device
 drivers along with sd, st and sr (disk, tape and CDROM respectively). Sg
 is more generalized (but lower level) than its siblings and tends to be
 used on SCSI devices that don't fit into the already serviced categories.
-Thus sg is used for scanners, cd writers and reading audio cds digitally
+Thus sg is used for scanners, CD writers and reading audio CDs digitally
 amongst other things.
 
-These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.39 . The original driver was written by Lawrence
-Foard and remained in place with minimal changes since circa 1992.
-Version 2 of this driver remains backward compatible (binary and
-source **) with the original. It adds scatter gather, command queuing,
-per file descriptor sequencing, asynchronous notification and better
-error reporting.
-
-This is an abridged version of the sg documentation that is targeted
-at the linux/Documentation directory. The full document can be found
-at http://www.torque.net/sg/p/scsi-generic_long.txt .
-
-The Linux 2.4 series kernels have now been released. Lk 2.4 contains
-an upgraded "version 3" sg driver which is described in a supplementary
-document at http://www.torque.net/sg/p/scsi-generic_v3.txt .
-
-The interface and usage of the original sg driver have been documented
-by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
-of the document is version 1.5 dated 7th May 1996. It can found at
-ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
-A copy of this document can be found at:
-http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO.txt .
-
-** It is possible to write applications that perform differently
-depending on whether they are using the original or this version of
-the sg device driver. The author is not aware of any useful
-pre-existing applications that have problems with version 2.
-
-
-Architecture
-============
-The SCSI generic packet device driver (sg) is a character based device.
-It is one of the four high level device driver in the SCSI sub-system;
-the others are sd (for direct-access devices - disks), st (for tapes)
-and sr (for data cdroms). Sd and sr are block devices while st (like sg)
-is a character device.
-
-The unifying layer of the SCSI sub-system is the so-called mid-level.
-Below that are the "low level" drivers which are the drivers for the
-various adapters supported by Linux. Also at this level are pseudo
-adapter drivers such as ide-scsi which converts the SCSI protocol to
-ATAPI (which are similar to one another) for use by IDE devices.
-
-Since sg is a character device it supports the traditional Unix
-system calls of open(), close(), read(), write() and ioctl(). Two other
-related system calls: poll() and fcntl() are added to this list and
-how they interact with the sg device driver is documented later.
-
-An SG device is accessed by write()ing SCSI commands plus any associated
-outgoing data to it; the resulting status codes and any incoming data are
-then obtained by a read() call. The device can be opened O_NONBLOCK
-(non-blocking) and poll() used to monitor its progress. The device may be
-opened O_EXCL which excludes other "sg" users from this device (but not
-"sd", "st" or "sr" users). The buffer given to the write() call is made
-up as follows:
-        - struct sg_header image (see below)
-        - scsi command (6, 10 or 12 bytes long)
-        - data to be written to the device (if any)
-
-The buffer received from the corresponding read() call contains:
-        - struct sg_header image (check status/errors + sense_buffer)
-        - data read back from device (if any)
-
-The given SCSI command has its LUN field overwritten by the LUN value of
-the associated sg device that has been open()ed.
-
-SCSI commands are only attempted once (i.e. there are no internal
-retries). If appropriate (e.g. a SCSI READ) the data buffer is copied back
-to user space irrespective of the values of the various SCSI related
-error/status codes. [Some adapters that use an old error interface in
-the SCSI mid level ignore the retry count and retry certain errors.]
-
-
-sg_header
-=========
-This is the name of the control structure that conveys information
-about the length of data to be read/written by the associated SCSI
-command. It also conveys error and status information from the
-read() call. An instance of this structure is the first thing that
-is placed in the data buffers of both write() and read().
-
-In its original form it looked like this:
-struct sg_header {
-    int pack_len;
-    int reply_len;
-    int pack_id;
-    int result;
-    unsigned int twelve_byte:1;
-    unsigned int other_flags:31;
-    unsigned char sense_buffer[16];
-}; /* this structure is 36 bytes long */
-
-The 'pack_len' is bizarre and ends up having the 'reply_len' put in it
-(perhaps it had a use at some stage). Even though it looks like an
-input variable, it is not read by sg internally (only written).
-
-The 'reply_len' is the length of the data the corresponding read()
-will/should request (including the sg_header).
-
-The 'pack_id' is not acted upon by the sg device driver but is conveyed
-back to the corresponding read() so it can be used for sequencing by an
-application.
-
-The 'result' is also bizarre, turning certain types of host codes to 0 (no
-error), EBUSY or EIO. With better error reporting now available, the
-'result' is best ignored.
-
-The 'twelve_byte' field overrides the internal SCSI command length detection
-algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
-a command length of 12 bytes.
-The command length detection algorithm is as follows:
-Group:  0    1    2    3    4    5    6    7
-Length: 6   10   10   12   12   12   10   10
-
-'other_flags' was originally documented as "not used" but some current
-applications assume it has 0 placed in it.
-
-The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is
-returned when the target returns a SCSI status code of CHECK_CONDITION
-or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
-buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
-this is unlikely to happen in the 2.2.x series of kernels.
-
-
-The new sg_header offered in this driver is:
-#define SG_MAX_SENSE 16
-struct sg_header
-{
-    int pack_len;    /* [o] reply_len (ie useless) ignored as input */
-    int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
-    int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
-    unsigned int twelve_byte:1;
-        /* [i] Force 12 byte command length for group 6 & 7 commands  */
-    unsigned int target_status:5;   /* [o] scsi status from target */
-    unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
-    unsigned int driver_status:8;   /* [o] driver status+suggestion */
-    unsigned int other_flags:10;    /* unused */
-    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
-           when target_status is CHECK_CONDITION or
-           when target_status is COMMAND_TERMINATED or
-           when (driver_status & DRIVER_SENSE) is true. */
-};      /* This structure is 36 bytes long on i386 */
-
-Firstly the new header is binary compatible with the original. This is
-important for keeping existing apps working without recompilation.
-
-Only those elements (or fields) that are new or in some way different
-from the original are documented below.
-
-'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID,
-&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest
-waiting packet; any other value will cause the read() to wait (or yield
-EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
-the value of 'pack_id' available after a read() is the value given to that
-variable in the prior, corresponding write().
-
-The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
-ioctl().
-
-The 'target_status' field is always output and is the (masked and shifted
-1 bit right) SCSI status code from the target device. The allowable
-values are (found in <scsi/scsi.h>):
-/* N.B. 1 bit offset from usual SCSI status values */
-#define GOOD                 0x00
-#define CHECK_CONDITION      0x01
-#define CONDITION_GOOD       0x02
-#define BUSY                 0x04
-#define INTERMEDIATE_GOOD    0x08
-#define INTERMEDIATE_C_GOOD  0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define COMMAND_TERMINATED   0x11
-#define QUEUE_FULL           0x14
-When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
-'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
-is true then the 'sense_buffer' is also output (this seems to occur when
-the ide-scsi emulation is used). When the 'sense_buffer' is output the
-SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
-
-The 'host_status' field is always output and has the following values
-whose "defines" are not visible outside the kernel. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DID_OK          0x00 /* NO error                                */
-#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
-#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
-#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
-#define DID_BAD_TARGET  0x04 /* BAD target, device not responding?      */
-#define DID_ABORT       0x05 /* Told to abort for some other reason     */
-#define DID_PARITY      0x06 /* Parity error                            */
-#define DID_ERROR       0x07 /* Internal error [DMA underrun on aic7xxx]*/
-#define DID_RESET       0x08 /* Reset by somebody.                      */
-#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
-#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
-#define DID_SOFT_ERROR  0x0b /* The low level driver wants a retry      */
-
-The 'driver_status' field is always output. When ('driver_status' &
-DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DRIVER_OK           0x00 /* Typically no suggestion */
-#define DRIVER_BUSY         0x01
-#define DRIVER_SOFT         0x02
-#define DRIVER_MEDIA        0x03
-#define DRIVER_ERROR        0x04
-#define DRIVER_INVALID      0x05
-#define DRIVER_TIMEOUT      0x06
-#define DRIVER_HARD         0x07
-#define DRIVER_SENSE        0x08 /* Implies sense_buffer output */
-/* above status 'or'ed with one of the following suggestions */
-#define SUGGEST_RETRY       0x10
-#define SUGGEST_ABORT       0x20
-#define SUGGEST_REMAP       0x30
-#define SUGGEST_DIE         0x40
-#define SUGGEST_SENSE       0x80
-
-'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
-code that places 0 in it will still be happy. It is not used.
-
-
-System Calls
-============
-What follows are descriptions of the characteristics of the standard
-Unix operating system calls when applied to a SCSI generic device
-using this version of the device driver.
-
-open(const char * filename, int flags)
---------------------------------------
-The filename should be an 'sg' device such as
-/dev/sg[0,1,2,...]
-/dev/sg[a-z]             <<< now deprecated >>>
-or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .]
-It seems as though SCSI devices are allocated to sg minor numbers in the
-same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character"
-based Linux device driver.  This means it has an open/close/read/write/ioctl
-type interface.
-
-Flags can be either O_RDONLY or O_RDWR or-ed with either
-O_EXCL          waits for other opens on sg device to be closed before
-                proceeding. If O_NONBLOCK is set then yields EBUSY when
-                someone else has the sg device open. The combination of
-                O_RDONLY and O_EXCL is disallowed.
-O_NONBLOCK      Sets non-blocking mode. Calls that would otherwise block
-                yield EAGAIN (eg read() ) or EBUSY (eg open() ).
-
-The original version of sg did not allow the O_RDONLY (yielding a EACCES
-error). This version allows it for accessing ioctls (e.g. doing an sg
-device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
-allowed. These flags are found in <fcntl.h> .
-
-By default, sequencing is per file descriptor in this version of sg. This
-means, for example that 2 processes can independently manipulate the same
-sg device at the same time. This may or may not make sense depending on
-the application: 2 processes (logically) reading from the same direct access
-device (ie a disk) is ok while running 2 instances of cd writing software
-on the same device at the same time probably wouldn't be a good idea. The
-previous version of sg supported only per device sequencing and this can
-still be selected with the SG_SET_MERGE_FD,1 ioctl().
-
-The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
-the current sg.h) on open(). The size of this reserved buffer can
-subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
-cases these are requests subject to various dynamic constraints. The actual
-amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
-The reserved buffer will be used if:
-    -  it is not already in use (eg when command queuing is in use)
-    -  a write() does not call for a buffer size larger than the
-       reserved size.
-
-Returns a file descriptor if >= 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES          Either the user doesn't have appropriate permissions on
-                'filename' or attempted to use both O_RDONLY and O_EXCL
-EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
-                set while someone is already using this device
-EINTR           while waiting for an "exclusive" lock to clear, a signal
-                is received, just try again ...
-ENODEV          sg not compiled into kernel or the kernel cannot find the
-                sg module (or it can't initialize itself (low memory??))
-ENOENT          given filename not found
-ENOMEM          An attempt to get memory to store this open's context
-                failed (this was _not_ a request to reserve DMA memory)
-ENXIO           either there is no attached device corresponding to given
-                filename or scsi sub-system is currently processing some
-                error (eg doing a device reset) or the sg driver/module
-                removed or corrupted
-
-
-write(int sg_fd, const void * buffer, size_t count)
----------------------------------------------------
-Even though sg is a character-based device driver it sends and receives
-packets to/from the associated scsi device. Write() is used to send a
-packet containing 2 mandatory parts and 1 optional part. The mandatory
-parts are:
-  - a control block (an instance of struct sg_header)
-  - a SCSI command (6, 10 or 12 bytes long)
-The optional part is:
-  - outgoing data (eg if a SCSI write command is being sent)
-These should appear as one contiguous string in the buffer given to
-write() in the above order with no pad characters.
-
-If a write() accepts this packet then at some later time the user should
-call a read() to get the result of the SCSI command. The previous sg
-driver enforced a strict write()/read()/write()/read() regime so that a
-second write() would block until first read() was finished. This sg
-driver relaxes that condition and thereby allows command queuing
-(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor).
-However, for backward compatibility, command queuing is turned off
-by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed
-via the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing
-the above define to 1].
-
-In this sg driver a write() should return more or less immediately.
-
-Returns number of bytes written if > 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES          opened with RD_ONLY flag
-EAGAIN          SCSI mid-level out of command blocks (rare), try again.
-                This is more likely to happen when queuing commands,
-                so wait a bit (eg usleep(10000) ) before trying again
-EDOM            a) command queuing off: a packet is already queued
-                b) command queuing on: too many packets queued
-                   (SG_MAX_QUEUE exceeded)
-EFAULT          'buffer' for 'count' bytes is an invalid memory range
-EIO             a) incoming buffer too short. It should be at least
-                   (6 + sizeof(struct sg_header))==42 bytes long
-                b) SCSI command length given in SG_NEXT_CMD_LEN too long
-                c) reply_len negative
-ENOMEM          can't get memory for DMA. Take evasive action ...
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
-
-
-read(int sg_fd, void * buffer, size_t count)
---------------------------------------------
-Read() is used to receive a packet containing 1 mandatory part and 1
-optional part. The mandatory part is:
-  - a control block (an instance of struct sg_header)
-The optional part is:
-  - incoming data (eg if a SCSI read command was sent by earlier write() )
-The buffer given to a read() and its corresponding count should be
-sufficient to accommodate this packet to avoid truncation. Truncation occurs
-if count < sg_header::replylen .
-
-By default, read() will return the oldest packet queued up. If the
-SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
-fetch the packet whose pack_id (given earlier to write()) matches the
-sg_header::pack_id given to this read(). If not available it will either
-wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
-to read() will match the oldest packet.
-
-Returns number of bytes read if > 0 , otherwise -1 implies an error.
-Unfortunately the return value in the non-error case is simply the
-same as the count argument. It is not the actual number of bytes
-DMA-ed by the SCSI device. This driver is currently unable to provide
-such an underrun indication.
-
-If the SCSI device reports an error then a REQUEST SENSE is automatically
-done and the output is placed in the sense_buffer array which is in the
-control block. This action is sometimes called "auto-sense".
-
-Error codes (value in 'errno' after -1 returned):
-EAGAIN          either no waiting packet or requested packet is not
-                available while O_NONBLOCK flag was set
-EFAULT          'buffer' for 'count' bytes is an invalid memory range
-EINTR           while waiting for a packet, a signal is received, just
-                try again ...
-EIO             if the 'count' given to read() is < sizeof(struct sg_header)
-                and the 'result' element in sg_header is non-zero. Not a
-                recommended error reporting technique
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
-
-
-close(int sg_fd)
-----------------
-Preferably a close() should be done after all issued write()s have had
-their corresponding read() calls completed. Unfortunately this is not
-always possible. The semantics of close() in Unix are to return more
-or less immediately (ie not wait on any event) so the driver needs to
-arrange for an orderly cleanup of those packets that are still "in
-flight".
-
-A process that has an open file descriptor to an sg device may be aborted
-(eg by a kill signal). In this case, the kernel automatically calls close
-(which is called 'sg_release()' in the version 2 driver) to facilitate
-the cleanup mentioned above.
-
-A problem persists in version 2.1.39 if the sg driver is a module and is
-removed while packets are still "in flight".
-
-Returns 0 if successful, otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-ENXIO           sg driver/module removed or corrupted
-
-ioctl(int sg_fd, int command, ...)  [sg specific]
--------------------------------------------------
-Ken Thompson (or perhaps some other Unix luminary) described ioctl() as
-the "garbage bin of Unix". This driver compounds the situation by adding
-more ...
-If a ioctl command is not recognized by sg (and the various lower levels
-that it may pass the command on to) then the error EINVAL occurs. If an
-invalid address is given (in the 3rd argument) then the error EFAULT occurs.
-
-Those commands with an appended "+" are new in version 2.
-
-Those commands with an appended "W" are only accessible from file
-descriptors opened with O_RDWR. They will yield EACCES otherwise.
-
-SG_GET_TIMEOUT:
-Ignores its 3rd argument and _returns_ the timeout value (which will be
->= 0 ). The unit of this timeout is "jiffies" which are currently 10
-millisecond intervals on i386 (less on an alpha). Linux supplies
-a manifest constant HZ which is the number of "jiffies" in 1 second.
-
-SG_SET_TIMEOUT:
-Assumes 3rd argument points to an int containing the new timeout value
-for this file descriptor. The unit is a "jiffy". Packets that are
-already "in flight" will not be affected. The default value is set
-on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
-currently 1 minute and may not be long enough for formats. Negative
-values will yield an EIO error.
-
-SG_EMULATED_HOST:
-Assumes 3rd argument points to an int and outputs a flag indicating
-whether the host (adapter) is connected to a real SCSI bus or is an
-emulated one (eg ide-scsi device driver). A value of 1 means emulated
-while 0 is not.
-
-SG_SET_TRANSFORM  W:
-Only is meaningful when SG_EMULATED host has yielded 1 (i.e. the low-level
-is the ide-scsi device driver); otherwise an EINVAL error occurs. The
-default state is to _not_ transform SCSI commands to the corresponding
-ATAPI commands but pass them straight through as is. [Only certain classes
-of SCSI commands need to be transformed to their ATAPI equivalents.]
-The third argument is interpreted as an integer. When it is non-zero then
-a flag is set inside the ide-scsi driver that transforms subsequent
-commands sent to this driver. When zero is passed as the 3rd argument to
-this ioctl then the flag within the ide-scsi driver is cleared and
-subsequent commands are not transformed. Beware, this state will affect
-all devices (and hence all related sg file descriptors) associated with
-this ide-scsi "bus".
-
-SG_GET_TRANSFORM:
-Third argument is ignored. Only is meaningful when SG_EMULATED host has
-yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
-an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
-to ATAPI commands (default). Returns 1 when it is transforming them.
-
-SG_SET_FORCE_LOW_DMA +:
-Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
-means sg decides whether to use memory above 16 Mbyte level (on i386)
-based on the host adapter being used by this SCSI device. Typically
-PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
-space.
-If 1 is given then the host adapter is overridden and only memory below
-the 16MB level is used for DMA. A requirement for this should be
-extremely rare. If the "reserved" buffer allocated on open() is not in
-use then it will be de-allocated and re-allocated under the 16MB level
-(and the latter operation could fail yielding ENOMEM).
-Only the current file descriptor is affected.
-
-SG_GET_LOW_DMA +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0
-indicates the whole 32 bit address space is being used for DMA transfers
-on this file descriptor. 1 indicates the memory below the 16MB level
-(on i386) is being used (and this may be the case because the host
-adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
-
-SG_GET_SCSI_ID +:
-Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
-sg.h) and populates it. That structure contains ints for host_no,
-channel, scsi_id, lun, scsi_type, allowable commands per lun and
-queue_depth. Most of this information is available from other sources
-(eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) but tends to be
-awkward to collect.
-Allowable commands per lun and queue_depth give an insight to the
-command queuing capabilities of the adapters and the device. The latter
-overrides the former (logically) and the former is only of interest
-if it is equal to queue_depth which probably indicates the device
-does not support queueing commands (e.g. most scanners).
-
-SG_SET_FORCE_PACK_ID +:
-Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
-to return the oldest (written) packet if multiple packets are
-waiting to be read (when command queuing is being used).
-1 instructs read() to view the sg_header::pack_id as input and return the
-oldest packet matching that pack_id or wait until it arrives (or yield
-EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
-given to read() in the mode will match the oldest packet.
-Only the current file descriptor is affected by this command.
-
-SG_GET_PACK_ID +:
-Assumes 3rd argument points to an int and places the pack_id of the
-oldest (written) packet in it. If no packet is waiting to be read then
-yields -1.
-
-SG_GET_NUM_WAITING +:
-Assumes 3rd argument points to an int and places the number of packets
-waiting to be read in it.
-
-SG_GET_SG_TABLESIZE +:
-Assumes 3rd argument points to an int and places the maximum number of
-scatter gather elements supported by the host adapter. 0 indicates that
-the adapter does support scatter gather.
-
-SG_SET_RESERVED_SIZE +W:
-Assumes 3rd argument is pointing to an int. That value will be used to
-request a new reserved buffer of that size. The previous reserved buffer
-is freed (if it is not in use; if it was in use -EBUSY is returned).
-A new reserved buffer is then allocated and its actual size can be found by
-calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
-for DMA purposes by subsequent write() commands if it is not already in
-use and if the write() is not calling for a buffer size larger than that
-reserved. The reserved buffer may well be a series of kernel buffers if the
-adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
-
-SG_GET_RESERVED_SIZE +:
-Assumes 3rd argument points to an int and places the size in bytes of
-the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
-ioctl() call on this fd.  The result can be 0 if memory is very tight. In
-this case it may not be wise to attempt something like burning a CD on
-this file descriptor.
-
-SG_SET_MERGE_FD +W:
-Assumes 3rd argument is pointing to an int. 0 (the default) causes all
-subsequent sequencing to be per file descriptor. 1 causes all subsequent
-sequencing to be per device. If this command tries to change the current
-state and there is one or more _other_ file descriptors using this sg
-device then an EBUSY error occurs. Per device sequencing was the original
-semantics and allowed, for example different processes to "share" the
-device, one perhaps write()ing with the other one read()ing. This command
-is supplied if anyone needs those semantics. Per file descriptor
-sequencing, perhaps with the use of the O_EXCL flag, seems more sensible.
-
-SG_GET_MERGE_FD +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-sequencing is per file descriptor. 1 implies sequencing is per device
-(original sg driver's semantics).
-
-SG_SET_COMMAND_Q +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
-a packet while one is already queued will result in a EDOM error.
-1 turns command queuing on.
-Changing the queuing state only affects write()s done after the change.
-Only the current file descriptor is affected by this command.
-
-SG_GET_COMMAND_Q +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that command queuing is off on this file descriptor. 1 implies command
-queuing is on.
-
-SG_SET_UNDERRUN_FLAG +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
-that underruns be flagged. [The only low level driver that acts on this
-at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
-Only the current file descriptor is affected by this command (unless
-"per device" sequencing has been selected).
-
-SG_GET_UNDERRUN_FLAG +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that underruns are not being reported. 1 implies that underruns are being
-reported (see SG_SET_UNDERRUN_FLAG for more details).
-
-SG_NEXT_CMD_LEN +:
-Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
-will be used as the SCSI command length of the next SCSI command sent to
-a write() on this fd. After that write() the SCSI command length logic is
-reset to use automatic length detection (ie depending on SCSI command group
-and the 'twelve_byte' field). If the current SCSI command length maximum of
-12 is exceeded then the affected write() will yield an EDOM error.
-Giving this ioctl() a value of 0 will set automatic length detection for
-the next write(). N.B. Only the following write() on this fd is affected by
-this ioctl().
-
-SG_GET_VERSION_NUM +:
-Assumes 3rd argument points to an int. The version number is then placed
-in that int. A sg version such as 2.1.36 will yield "20136" from this ioctl.
-
-SG_SCSI_RESET +:
-Assumes 3rd argument points to an int. Unfortunately doesn't currently
-do much (may in the future after other issues are resolved). Yields an
-EBUSY error if the SCSI bus or the associated device is being reset
-when this ioctl() is called, otherwise returns 0.
-N.B. In some recent distributions there is a patch to the SCSI mid level
-code that activates this ioctl. Check your distribution.
-
-SG_SET_DEBUG +:
-Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
-off. Values > 0 cause the SCSI sense buffer to be decoded and output
-to the console/log when a SCSI device error occurs. Values > 8 cause
-the current sg device driver's state to be output to the console/log
-(this is a "one off" effect).
-If you need a _lot_ of the SCSI sub-system debug information (mainly from
-the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
-debug will appear in your console/log.
-
-
-poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
---------------------------------------------------------------
-This is a native call in Linux 2.2 but most of its capabilities are available
-through the older select() call. Given a choice poll() should probably be
-used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
-for polling; and optionally with asynchronous notification as well using
-the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
-Only if something drastically is wrong (eg file handle gone stale) will
-POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
-POLLIN is set when there is one or more packets waiting to be read.
-When POLLIN is set it implies that a read() will not block (nor yield
-EAGAIN in non-blocking mode) but return a packet immediately.
-POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
-(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
-by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
-set until the number of queued packets reaches SG_MAX_QUEUE, if the
-state is off then POLLOUT is only set when no packets are queued.
-Note that a packet can be queued after write()ing but not available to be
-read(); this typically happens when a SCSI read command is issued while
-the data is being retrieved.
-Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
-it is per device.
-
-
-fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
-----------------------------------------------------------------
-There are several uses for this system call in association with a sg
-file descriptor. The following pseudo code shows code that is useful for
-scanning the sg devices, taking care not to be caught in a wait for
-an O_EXCL lock by another process, and when the appropriate device is
-found, switching to normal blocked io. A working example of this logic
-is in the sg_scan utility program.
-
-open("/dev/sg0", O_RDONLY | O_NONBLOCK)
-/* check device, EBUSY means some other process has O_EXCL lock on it */
-/* when the device you want is found then ... */
-flags = fcntl(sg_fd, F_GETFL)
-fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
-/* since, for simple apps, it is easier to use normal blocked io */
-
-
-Some work has to be done in Linux to set up for asynchronous notification.
-This is a non-blocking mode of operation in which, when the driver receives
-data back from a device so that a read() can be done, it sends a SIGPOLL
-(aka SIGIO) signal to the owning process. A working example of this logic
-is in the sg_poll test program.
-
-sigemptyset(&sig_set)
-sigaddset(&sig_set, SIGPOLL)
-sigaction(SIGPOLL, &s_action, 0)
-fcntl(sg_fd, F_SETOWN, getpid())
-flags = fcntl(sg_fd, F_GETFL);
-fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
-
-
-Utility and Test Programs
-=========================
-See the README file in the sg_utils<date>.tgz tarball. Look on the
-http://www.torque.net/sg website for the latest version.
-
-Briefly, that tarball contains the following utilities:
-sg_dd512        'dd' like program that assumes 512 byte blocks size
-sg_dd2048       'dd' like program that assumes 2048 byte blocks size
-sg_dd2352       'dd' like program that assumes 2352 byte blocks size
-sgq_dd512       like 'sg_dd512' but does command queuing on "if"
-sgp_dd          probably the most flexible 'dd' variant. It uses POSIX
-                threads, block size set by "bs=..." plus other options.
-sg_scan         outputs information (optionally Inquiry) on SCSI devices
-sg_rbuf         tests SCSI bus transfer speed (without physical IO)
-sg_whoami       outputs info (optionally capacity) of given SCSI device
-sginfo          outputs "mode" information about SCSI devices (it is a
-                  re-port of the scsiinfo program onto the sg interface)
-
-It also contains the following test programs:
-sg_debug        outputs sg driver state to console/log file
-sg_poll         tests asynchronous notification
-sg_runt_ex      example run time selection program for application authors
-sg_simple1      example program first time users
-sg_simple2      like sg_simple1 but with more primitive error processing
-sg_inquiry      does a SCSI Inquiry command (from original HOWTO)
-sg_tst_med      checks presence of media (from original HOWTO)
-
-There are also 2 source files (sg_err.[hc]) for outputting and categorizing
-SCSI 2 errors and warnings. This code is used by most of the above
-utility and test programs.
-
-The following programs: sg_dd512, sg_dd2048, sg_dd2352, sg_scan, sg_runt_ex,
-sg_rbuf, sg_tst_med, sg_inquiry and sginfo, can be compiled either for this
-new sg driver _or_ the original sg driver (in 2.0 or 2.2 series kernels).
-sg_runt_ex can be run on 2.0, 2.2 or 2.3 series kernels even if it is
-compiled on a different series (eg compiled on 2.0, run on 2.2).
-
-
-Header files
-============
-User applications need to find the correct "sg.h" header file matching
-their kernel in order to write code using the sg device driver. This is
-sometimes more difficult than it should be. The correct "sg.h" will usually
-be found at /usr/src/linux/include/scsi/sg.h . Another important header
-file is "scsi.h" which will be in the same directory.
-
-When "#include <scsi/sg.h>" is written in an application then this refers
-to the file /usr/include/scsi/sg.h . A problem sometimes arises because
-the files in the /usr/include/scsi directory are controlled by the GNU
-library people who maintain glibc. Unfortunately these 2 versions of
-the sg.h header file are not always in sync. [This was the case in Redhat
-6.0 and 6.1 .] Glibc 2.1.3 and later versions should get this right.
-
-If this is a problem, the user may need to copy sg.h (and scsi.h) from
-the kernel source includes to /usr/include scsi. If the user can change
-the effected source code then another approach is to rely on the fact that
-/usr/src/linux is a symbolic link to /usr/src/linux/include/linux and
-change the sg.h include to look like:
-    #include <linux/../scsi/sg.h>
-This solution is used by the author of cdparanoia (Monty) in his application.
-
-[Former scsi generic documents suggested adding a symbolic link to
-bypass this problem but that is not popular with the glibc maintainers.
-I would like to thank Andreas Jaeger <aj@suse.de> for his contributions
-on this subject.]
-
-
-Extra information in scsi-generic_long.txt
-==========================================
-This document is an abridged form of a more comprehensive document called
-scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
-
-The longer document contains additional sections on:
-   - memory issues
-   - ioctl()s in common with sd, st + sr
-   - distinguishing the original from the new driver
-   - SG_BIG_BUFF and friends
-   - shortcomings
-   - future directions
-   - an appendix with some SCSI 2 information in it
-
-
-References
-==========
-http://www.t10.org      Very important site for SCSI related information.
-                        Contains SCSI 2 and 3 draft standards.
-http://www.andante.org/scsi.html
-                        This is Eric Youngdale's site. Eric is primarily
-                        responsible for the Linux SCSI architecture and
-                        its mid-level implementation.
-http://www.kernel.dk    Jens Axboe's site for Linux cdrom matters including
-                        the SCSI "sr" driver.
-http://www.torque.net/sg
-                        My site with sg related information.
-newsgroup:linux-scsi@vger.kernel.org
-                        Newsgroup for Linux related SCSI matters
-/usr/src/linux/MAINTAINERS
-                        This is a file in the Linux kernel source that
-                        contains up to date information about who maintains
-                        what and where information can be found. Links to
-                        SCSI adapter information are also here.
-
-
-Conclusion
-==========
-The SCSI generic packet device driver attempts to make as few assumptions
-as possible about the device it is connected to while giving applications
-using it as much flexibility as possible on the SCSI command level. Sg
-needs to hide the "messy" kernel related details while protecting
-the integrity of the kernel against sg "abuse". Some of these aims are
-contradictory and some compromises need to be made. For example: should
-a sg based application be able to reset a SCSI bus when that could cause
-collateral damage to a disk holding the root file system? There is no
-easy answer to this and many other related questions.
-
-If you have any suggestion about sg (or improving (the accuracy of) this
-document) please contact me.
+Rather than document the driver's interface here, version information
+is provided plus pointers (i.e. URLs) where to find documentation
+and examples.
+
+
+Major versions of the sg driver
+===============================
+There are three major versions of sg found in the linux kernel (lk):
+      - sg version 1 (original) from 1992 to early 1999 (lk 2.2.5) . 
+	It is based in the sg_header interface structure.
+      - sg version 2 from lk 2.2.6 in the 2.2 series. It is based on
+	an extended version of the sg_header interface structure.
+      - sg version 3 found in the lk 2.4 series (and the lk 2.5 series).
+	It adds the sg_io_hdr interface structure.
+
+
+Sg driver documentation
+=======================
+The most recent documentation of the sg driver is kept at the Linux
+Documentation Project's (LDP) site: 
+http://www.linuxdoc.org/HOWTO/SCSI-Generic-HOWTO
+This describes the sg version 3 driver found in the lk 2.4 series.
+The LDP renders documents in single and multiple page HTML, postscript
+and pdf. This document can also be found at:
+http://www.torque.net/sg/p/sg_v3_ho.html
+
+Documentation for the version 2 sg driver found in the lk 2.2 series can
+be found at http://www.torque.net/sg/p/scsi-generic.txt . A larger version
+is at:  http://www.torque.net/sg/p/scsi-generic_long.txt .
+
+The original documentation for the sg driver (prior to lk 2.2.6) can be
+found at http://www.torque.net/sg/p/original/SCSI-Programming-HOWTO.txt
+and in the LDP archives.
+
+A changelog with brief notes can be found in the
+/usr/src/linux/include/scsi/sg.h file. Note that the glibc maintainers copy 
+and edit this file (removing its changelog for example) before placing it 
+in /usr/include/scsi/sg.h . Driver debugging information and other notes 
+can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file.
+
+A more general description of the Linux SCSI subsystem of which sg is a 
+part can be found at http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO .
+
+
+Example code and utilities
+==========================
+There are two packages of sg utilities:
+  - sg3_utils   for the sg version 3 driver found in lk 2.4
+  - sg_utils    for the sg version 2 (and original) driver found in lk 2.2
+                and earlier
+Both packages will work in the lk 2.4 series however sg3_utils offers more
+capabilities. They can be found at: http://www.torque.net/sg and 
+freshmeat.net
+
+Another approach is to look at the applications that use the sg driver.
+These include cdrecord, cdparanoia, SANE and cdrdao.
+
+
+Mapping of Linux kernel versions to sg driver versions
+======================================================
+Here is a list of linux kernels in the 2.4 series that had new version
+of the sg driver:
+      lk 2.4.0 : sg version 3.1.17
+      lk 2.4.7 : sg version 3.1.19 
+      lk 2.4.10 : sg version 3.1.20  **
+      lk 2.4.17 : sg version 3.1.22 
+
+** There were 3 changes to sg version 3.1.20 by third parties in the
+   next six linux kernel versions.
+
+For reference here is a list of linux kernels in the 2.2 series that had 
+new version of the sg driver:
+      lk 2.2.0 : original sg version [with no version number]
+      lk 2.2.6 : sg version 2.1.31
+      lk 2.2.8 : sg version 2.1.32
+      lk 2.2.10 : sg version 2.1.34 [SG_GET_VERSION_NUM ioctl first appeared]
+      lk 2.2.14 : sg version 2.1.36
+      lk 2.2.16 : sg version 2.1.38
+      lk 2.2.17 : sg version 2.1.39
+      lk 2.2.20 : sg version 2.1.40
+
+The lk 2.5 development series has recently commenced and it currently
+contains sg version 3.5.23 which is functionally equivalent to sg
+version 3.1.22 found in lk 2.4.17 .
 
 
 Douglas Gilbert
+26th January 2002
 dgilbert@interlog.com
diff -urN linux-2.4.18-pre7/Documentation/scsi.txt linux/Documentation/scsi.txt
--- linux-2.4.18-pre7/Documentation/scsi.txt	Tue Apr 28 14:22:04 1998
+++ linux/Documentation/scsi.txt	Mon Feb  4 12:55:43 2002
@@ -1,30 +1,44 @@
+SCSI subsystem documentation
+============================
+The Linux Documentation Project (LDP) maintains a document describing
+the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
+http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
+and multiple page HTML renderings as well as postscript and pdf.
+It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO .
 
-	The scsi support in the linux kernel can be modularized in a
-number of different ways depending upon the needs of the end user.  To
-understand  your options, we should first define a few terms.
-
-	The scsi-core contains the core of scsi support.  Without it
-you can do nothing with any of the other scsi drivers.  The scsi core
-support can be a module (scsi_mod.o), or it can be built into the kernel.
-If the core is a module, it must be the first scsi module loaded, and
-if you unload the modules, it will have to be the last one unloaded.
-
-	The individual upper and lower level drivers can be loaded in any
-order once the scsi core is present in the kernel (either compiled in
-or loaded as a module).  The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
-tape driver (st.o) and scsi generics driver (sg.o) represent the upper level
-drivers to support the various assorted devices which can be controlled.
-You can for example load the tape driver to use the tape drive, and then
-unload it once you have no further need for the driver (and release the
-associated memory).
-
-	The lower level drivers are the ones that support the
-individual cards that are supported for the hardware platform that you
-are running under.  Examples are aha1542.o to drive Adaptec 1542
-cards.  Rather than list the drivers which *can* be modularized, it is
-easier to list the ones which cannot, since the list only contains a
-few entries.  The drivers which have NOT been modularized are:
 
-	NCR5380 boards of one kind or another including PAS16,
-		Trantor T128/128F/228, 
+Notes on using modules in the SCSI subsystem
+============================================
+The scsi support in the linux kernel can be modularized in a number of 
+different ways depending upon the needs of the end user.  To understand
+your options, we should first define a few terms.
+
+The scsi-core (also known as the "mid level") contains the core of scsi 
+support.  Without it you can do nothing with any of the other scsi drivers.
+The scsi core support can be a module (scsi_mod.o), or it can be built into
+the kernel. If the core is a module, it must be the first scsi module 
+loaded, and if you unload the modules, it will have to be the last one 
+unloaded.  In practice the modprobe and rmmod commands (and "autoclean")
+will enforce the correct ordering of loading and unloading modules in
+the SCSI subsystem.
+
+The individual upper and lower level drivers can be loaded in any order 
+once the scsi core is present in the kernel (either compiled in or loaded
+as a module).  The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
+tape driver ** (st.o) and scsi generics driver (sg.o) represent the upper 
+level drivers to support the various assorted devices which can be 
+controlled.  You can for example load the tape driver to use the tape drive, 
+and then unload it once you have no further need for the driver (and release
+the associated memory).
+
+The lower level drivers are the ones that support the individual cards that
+are supported for the hardware platform that you are running under. Those
+individual cards are often called Host Bus Adapters (HBAs). For example the
+aic7xxx.o driver is used to control all recent SCSI controller cards from 
+Adaptec. Almost all lower level drivers can be built either as modules or 
+built into the kernel.
+
+
+** There is a variant of the st driver for controlling OnStream tape
+   devices. Its module name is osst.o .
 
diff -urN linux-2.4.18-pre7/Documentation/sound/AD1816 linux/Documentation/sound/AD1816
--- linux-2.4.18-pre7/Documentation/sound/AD1816	Wed Sep 27 13:53:52 2000
+++ linux/Documentation/sound/AD1816	Mon Feb  4 12:55:43 2002
@@ -80,5 +80,5 @@
   tek@rbg.informatik.tu-darmstadt.de
 
 Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
-Christoph Hellwig <hch@caldera.de>
+Christoph Hellwig <hch@infradead.org>
 	Last modified: 2000/09/20
diff -urN linux-2.4.18-pre7/Documentation/sound/NEWS linux/Documentation/sound/NEWS
--- linux-2.4.18-pre7/Documentation/sound/NEWS	Wed Sep 27 13:53:52 2000
+++ linux/Documentation/sound/NEWS	Mon Feb  4 12:55:43 2002
@@ -1,6 +1,6 @@
 Linux 2.4 Sound Changes
 2000-September-25
-Christoph Hellwig, <hch@caldera.de>
+Christoph Hellwig, <hch@infradead.org>
 
 
 
@@ -9,9 +9,6 @@
 The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
 Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
 detecting and configuring isapnp devices.
-If you have a not yet supported isapnp soundcard, mail me the content
-of '/proc/isapnp' on your system and some information about your card
-and its driver(s) so I can try to get isapnp working for it.
 
 
 
diff -urN linux-2.4.18-pre7/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.18-pre7/MAINTAINERS	Mon Feb  4 12:55:36 2002
+++ linux/MAINTAINERS	Mon Feb  4 12:55:43 2002
@@ -582,7 +582,7 @@
 
 FREEVXFS FILESYSTEM
 P:	Christoph Hellwig
-M:	hch@caldera.de
+M:	hch@infradead.org
 W:	ftp://ftp.openlinux.org/pub/people/hch/vxfs
 S:	Maintained
 
@@ -1177,9 +1177,9 @@
 
 PERSONALITY HANDLING
 P:	Christoph Hellwig
-M:	hch@caldera.de
+M:	hch@infradead.org
 L:	linux-abi-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 PCI ID DATABASE
 P:	Jens Maurer
@@ -1473,7 +1473,7 @@
 
 SYSV FILESYSTEM
 P:	Christoph Hellwig
-M:	hch@caldera.de
+M:	hch@infradead.org
 S:	Maintained
 
 TLAN NETWORK DRIVER
diff -urN linux-2.4.18-pre7/Makefile linux/Makefile
--- linux-2.4.18-pre7/Makefile	Mon Feb  4 12:55:36 2002
+++ linux/Makefile	Mon Feb  4 12:55:43 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION = -pre7
+EXTRAVERSION = -pre8
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.18-pre7/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- linux-2.4.18-pre7/arch/alpha/kernel/time.c	Sat Nov 17 11:47:44 2001
+++ linux/arch/alpha/kernel/time.c	Mon Feb  4 12:55:43 2002
@@ -379,8 +379,6 @@
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
 
-	do_get_fast_time = do_gettimeofday;
-
 	/*
 	 * If we had wanted SRM console printk echoing early, undo it now.
 	 *
diff -urN linux-2.4.18-pre7/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.4.18-pre7/arch/i386/config.in	Mon Feb  4 12:55:37 2002
+++ linux/arch/i386/config.in	Mon Feb  4 12:55:43 2002
@@ -147,18 +147,21 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE y
 fi
 if [ "$CONFIG_MWINCHIP2" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE y
 fi
 if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_OOSTORE y
 fi
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 tristate 'Dell laptop support' CONFIG_I8K
diff -urN linux-2.4.18-pre7/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
--- linux-2.4.18-pre7/arch/i386/kernel/apic.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/i386/kernel/apic.c	Mon Feb  4 12:55:43 2002
@@ -88,8 +88,12 @@
 		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
 	if (maxlvt >= 4)
 		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
-	apic_write(APIC_ESR, 0);
-	v = apic_read(APIC_ESR);
+	v = GET_APIC_VERSION(apic_read(APIC_LVR));
+	if (APIC_INTEGRATED(v)) {	/* !82489DX */
+		if (maxlvt > 3)
+			apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
 }
 
 void __init connect_bsp_APIC(void)
diff -urN linux-2.4.18-pre7/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- linux-2.4.18-pre7/arch/i386/kernel/entry.S	Fri Nov  2 17:18:49 2001
+++ linux/arch/i386/kernel/entry.S	Mon Feb  4 12:55:43 2002
@@ -622,6 +622,18 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* Reserved for Security */
 	.long SYMBOL_NAME(sys_gettid)
 	.long SYMBOL_NAME(sys_readahead)	/* 225 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for setxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for lsetxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fsetxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for getxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 230 reserved for lgetxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fgetxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for listxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for llistxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for flistxattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 235 reserved for removexattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for lremovexattr */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fremovexattr */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.4.18-pre7/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- linux-2.4.18-pre7/arch/i386/kernel/time.c	Sun Nov 11 10:20:21 2001
+++ linux/arch/i386/kernel/time.c	Mon Feb  4 12:55:43 2002
@@ -681,7 +681,6 @@
 #ifndef do_gettimeoffset
 			do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-			do_get_fast_time = do_gettimeofday;
 
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
diff -urN linux-2.4.18-pre7/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- linux-2.4.18-pre7/arch/ia64/kernel/time.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/time.c	Mon Feb  4 12:55:43 2002
@@ -145,9 +145,6 @@
 	tv->tv_usec = usec;
 }
 
-/* XXX there should be a cleaner way for declaring an alias... */
-asm (".global get_fast_time; get_fast_time = do_gettimeofday");
-
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
diff -urN linux-2.4.18-pre7/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- linux-2.4.18-pre7/arch/ppc/kernel/entry.S	Mon Nov 26 05:29:17 2001
+++ linux/arch/ppc/kernel/entry.S	Mon Feb  4 12:55:43 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.entry.S 1.24 11/23/01 16:38:29 paulus
+ * BK Id: SCCS/s.entry.S 1.26 01/25/02 15:15:24 benh
  */
 /*
  *  PowerPC version 
@@ -338,13 +338,24 @@
 	REST_4GPRS(3, r1)
 	REST_2GPRS(7, r1)
 
+#ifndef CONFIG_SMP
 	/* We have to "dummy" load from the context save area in case
 	 * these instructions cause an MMU fault.  If this happens
 	 * after we load SRR0/SRR1, our return context is hosed.  -- Dan
+	 * 
+	 * This workaround is not enough, we must also make sure the
+	 * actual code for this routine is in the TLB or BAT mapped.
+	 * For 6xx/Power3, we know the code is in a BAT, so this should
+	 * be enough in UP. In SMP, I limit lowmem to the amount of
+	 * RAM that can be BAT mapped. Other CPUs may need additional
+	 * tweaks, especially if used SMP or if the code for this routine
+	 * crosses page boundaries. The TLB pin down for 4xx should help
+	 * for example. --BenH.
 	 */
 	lwz	r0,GPR0(r1)
 	lwz	r0,GPR2(r1)
 	lwz	r0,GPR1(r1)
+#endif /* ndef CONFIG_SMP */
 
 	/* We re-use r3,r4 here (the load above was to cause the MMU
 	 * fault if necessary).  Using r3,r4 removes the need to "dummy"
diff -urN linux-2.4.18-pre7/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- linux-2.4.18-pre7/arch/ppc/kernel/pci.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/ppc/kernel/pci.c	Mon Feb  4 12:55:43 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pci.c 1.38 12/11/01 14:57:05 benh
+ * BK Id: SCCS/s.pci.c 1.40 01/25/02 15:15:24 benh
  */
 /*
  * Common pmac/prep/chrp pci routines. -- Cort
@@ -284,9 +284,17 @@
 			if (bus->parent == NULL)
 				pr = (res->flags & IORESOURCE_IO)?
 					&ioport_resource: &iomem_resource;
-			else
+			else {
 				pr = pci_find_parent_resource(bus->self, res);
-
+				if (pr == res) {
+					/* this happens when the generic PCI
+					 * code (wrongly) decides that this
+					 * bridge is transparent  -- paulus
+					 */
+					continue;
+				}
+			}
+			
 			if (pr && request_resource(pr, res) == 0)
 				continue;
 			printk(KERN_ERR "PCI: Cannot allocate resource region "
diff -urN linux-2.4.18-pre7/arch/ppc/kernel/pmac_feature.c linux/arch/ppc/kernel/pmac_feature.c
--- linux-2.4.18-pre7/arch/ppc/kernel/pmac_feature.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/ppc/kernel/pmac_feature.c	Mon Feb  4 12:55:43 2002
@@ -792,12 +792,12 @@
 	}
     	LOCK(flags);
     	if (value) {
-    		MACIO_BIC(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+    		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
 	    	UNLOCK(flags);
 	    	(void)MACIO_IN32(KEYLARGO_FCR2);
 		mdelay(250);
     	} else {
-    		MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+    		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
 	    	UNLOCK(flags);
     	}
 	if (value) {
@@ -960,7 +960,7 @@
 		mdelay(10);
 
 		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
 		(void)MACIO_IN32(KEYLARGO_FCR2);
 		udelay(10);
 		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
@@ -985,7 +985,7 @@
 		(void)MACIO_IN8(0x1a3e0);
 		udelay(10);
 		LOCK(flags);
-		MACIO_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
+		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
 		(void)MACIO_IN32(KEYLARGO_FCR2);
 		UNLOCK(flags);
 		mdelay(100);
@@ -993,7 +993,7 @@
 		macio->flags |= MACIO_FLAG_AIRPORT_ON;
 	} else {
 		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
 		(void)MACIO_IN32(KEYLARGO_FCR2);
 		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
 		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
@@ -1085,20 +1085,20 @@
 			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
 		}
 		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg &=	~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
-			KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number));
-		reg &=	~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
-			KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1));
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
 		MACIO_OUT32(KEYLARGO_FCR4, reg);
 		(void)MACIO_IN32(KEYLARGO_FCR4);
 		udelay(10);
 	} else {
 		/* Turn OFF */
 		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg |=	KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
-			KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number);
-		reg |=	KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
-			KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
 		MACIO_OUT32(KEYLARGO_FCR4, reg);
 		(void)MACIO_IN32(KEYLARGO_FCR4);
 		udelay(1);
@@ -1155,9 +1155,7 @@
 	struct macio_chip* macio;
 
 	/* Trick: we allow NULL node */
-	if (pmac_mb.model_id != PMAC_TYPE_FW_IBOOK &&
-	    pmac_mb.model_id != PMAC_TYPE_PISMO &&
-	    pmac_mb.model_id != PMAC_TYPE_IBOOK2)
+	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
 	    	return -ENODEV;
 	macio = &macio_chips[0];
 	if (macio->type != macio_keylargo && macio->type != macio_pangea)
@@ -1228,7 +1226,7 @@
 		KL1_UIDE_ENABLE);
 	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
 
-	MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
  	udelay(10);
  	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
  	udelay(10);
@@ -1267,7 +1265,7 @@
 		KL1_UIDE_ENABLE);
 	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
 
-	MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
  	udelay(10);
 	temp = MACIO_IN32(KEYLARGO_FCR3);
 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
@@ -1665,7 +1663,7 @@
 	},
 	{	"PowerBook4,1",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
 	{	"PowerMac1,1",			"Blue&White G3",
 		PMAC_TYPE_YOSEMITE,		paddington_features,
@@ -1701,7 +1699,7 @@
 	},
 	{	"PowerBook2,2",			"iBook FireWire",
 		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
 	{	"PowerMac5,1",			"PowerMac G4 Cube",
 		PMAC_TYPE_CUBE,			core99_features,
@@ -1716,15 +1714,15 @@
 	},
 	{	"PowerBook3,1",			"PowerBook Pismo",
 		PMAC_TYPE_PISMO,		core99_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
 	{	"PowerBook3,2",			"PowerBook Titanium",
 		PMAC_TYPE_TITANIUM,		core99_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
 	{	"PowerBook3,3",			"PowerBook Titanium II",
 		PMAC_TYPE_TITANIUM2,		core99_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
 };
 
@@ -1970,6 +1968,35 @@
 }
 
 static void __init
+initial_serial_shutdown(struct device_node* np)
+{
+	int len;
+	struct slot_names_prop {
+		int	count;
+		char	name[1];
+	} *slots;
+	char *conn;
+	int port_type = PMAC_SCC_ASYNC;
+	int modem = 0;
+	
+	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+	conn = get_property(np, "AAPL,connector", &len);
+	if (conn && (strcmp(conn, "infrared") == 0))
+		port_type = PMAC_SCC_IRDA;
+	else if (device_is_compatible(np, "cobalt"))
+		modem = 1;
+	else if (slots && slots->count > 0) {
+		if (strcmp(slots->name, "IrDA") == 0)
+			port_type = PMAC_SCC_IRDA;
+		else if (strcmp(slots->name, "Modem") == 0)
+			modem = 1;
+	}
+	if (modem)
+		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
+	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
+}
+
+static void __init
 set_initial_features(void)
 {
 	struct device_node* np;
@@ -1999,17 +2026,25 @@
 		 */
 		np = find_devices("ethernet");
 		while(np) {
-			if (np && device_is_compatible(np, "gmac"))
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && device_is_compatible(np, "gmac"))
 				core99_gmac_enable(np, 0, 1);
 			np = np->next;
 		}
 
 		/* Enable FW before PCI probe. Will be disabled later on
+		 * Note: We should have a batter way to check that we are
+		 * dealing with uninorth internal cell and not a PCI cell
+		 * on the external PCI. The code below works though.
 		 */
 		np = find_devices("firewire");
 		while(np) {
-			if (device_is_compatible(np, "pci106b,18") || 
-	     		    device_is_compatible(np, "pci106b,30")) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && (device_is_compatible(np, "pci106b,18") || 
+	     		        device_is_compatible(np, "pci106b,30") ||
+	     		        device_is_compatible(np, "pci11c1,5811"))) {
 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
 				core99_firewire_enable(np, 0, 1);
 			}
@@ -2031,9 +2066,21 @@
 	if (macio_chips[0].of_node)
 		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
 			macio_chips[0].of_node, 0, 0);
-			
+
+	/* On all machines, switch modem & serial ports off */
+	np = find_devices("ch-a");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+	np = find_devices("ch-b");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+	
 	/* Let hardware settle down */
-	mdelay(1);
+	mdelay(10);
 }
 
 void __init
diff -urN linux-2.4.18-pre7/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- linux-2.4.18-pre7/arch/ppc/kernel/pmac_pci.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/ppc/kernel/pmac_pci.c	Mon Feb  4 12:55:43 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pci.c 1.29 12/01/01 20:09:06 benh
+ * BK Id: SCCS/s.pmac_pci.c 1.31 01/20/02 23:53:11 benh
  */
 /*
  * Support for PCI bridges found on Power Macintoshes.
@@ -529,27 +529,35 @@
 {
 	struct device_node* node;
 	int updatecfg = 0;
-
+	int uninorth_child;
+	
 	node = pci_device_to_OF_node(dev);
-
+	
 	/* We don't want to enable USB controllers absent from the OF tree
 	 * (iBook second controller)
 	 */
 	if (dev->vendor == PCI_VENDOR_ID_APPLE
 	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
 		return -EINVAL;
+
+	if (!node)
+		return 0;
+		
+	uninorth_child = node->parent &&
+		device_is_compatible(node->parent, "uni-north");
 		
 	/* Firewire & GMAC were disabled after PCI probe, the driver is
 	 * claiming them, we must re-enable them now.
 	 */
-	if (node && !strcmp(node->name, "firewire") && 
+	if (uninorth_child && !strcmp(node->name, "firewire") && 
 	    (device_is_compatible(node, "pci106b,18") || 
-	     device_is_compatible(node, "pci106b,30"))) {
+	     device_is_compatible(node, "pci106b,30") ||
+	     device_is_compatible(node, "pci11c1,5811"))) {
 		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
 		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
 		updatecfg = 1;
 	}
-	if (node && !strcmp(node->name, "ethernet") && 
+	if (uninorth_child && !strcmp(node->name, "ethernet") && 
 	    device_is_compatible(node, "gmac")) {
 		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
 		updatecfg = 1;
@@ -608,7 +616,8 @@
 	nd = find_devices("firewire");
 	while (nd) {
 		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
-					device_is_compatible(nd, "pci106b,30"))
+				   device_is_compatible(nd, "pci106b,30") ||
+				   device_is_compatible(nd, "pci11c1,5811"))
 		    && device_is_compatible(nd->parent, "uni-north")) {
 			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
 			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
diff -urN linux-2.4.18-pre7/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- linux-2.4.18-pre7/arch/ppc/kernel/time.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/ppc/kernel/time.c	Mon Feb  4 12:55:44 2002
@@ -352,8 +352,6 @@
         	tz.tz_dsttime = 0;
         	do_sys_settimeofday(NULL, &tz);
         }
-
-       do_get_fast_time = do_gettimeofday;
 }
 
 #define FEBRUARY		2
diff -urN linux-2.4.18-pre7/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.4.18-pre7/arch/ppc/mm/init.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/ppc/mm/init.c	Mon Feb  4 12:55:44 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.38 12/01/01 20:09:07 benh
+ * BK Id: SCCS/s.init.c 1.40 01/25/02 15:15:24 benh
  */
 /*
  *  PowerPC version 
@@ -49,8 +49,6 @@
 #include "mem_pieces.h"
 #include "mmu_decl.h"
 
-#define MAX_LOW_MEM	(0xF0000000UL - KERNELBASE)
-
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 void *end_of_DRAM;
@@ -100,8 +98,6 @@
 
 /* max amount of RAM to use */
 unsigned long __max_memory;
-/* max amount of low RAM to map in */
-unsigned long __max_low_memory = MAX_LOW_MEM;
 
 int do_check_pgt_cache(int low, int high)
 {
@@ -316,12 +312,7 @@
 	if (__max_memory && total_memory > __max_memory)
 		total_memory = __max_memory;
 	total_lowmem = total_memory;
-	if (total_lowmem > __max_low_memory) {
-		total_lowmem = __max_low_memory;
-#ifndef CONFIG_HIGHMEM
-		total_memory = total_lowmem;
-#endif /* CONFIG_HIGHMEM */
-	}
+	adjust_total_lowmem();	
 	end_of_DRAM = __va(total_lowmem);
 	set_phys_avail(total_lowmem);
 
diff -urN linux-2.4.18-pre7/arch/ppc/mm/mmu_decl.h linux/arch/ppc/mm/mmu_decl.h
--- linux-2.4.18-pre7/arch/ppc/mm/mmu_decl.h	Fri Nov  2 17:43:54 2001
+++ linux/arch/ppc/mm/mmu_decl.h	Mon Feb  4 12:55:44 2002
@@ -24,7 +24,8 @@
  */
 
 extern void mapin_ram(void);
-extern void bat_mapin_ram(void);
+extern void bat_mapin_ram(unsigned long bat2, unsigned long bat3);
+extern void adjust_total_lowmem(void);
 extern int map_page(unsigned long va, unsigned long pa, int flags);
 extern void setbat(int index, unsigned long virt, unsigned long phys,
 		   unsigned int size, int flags);
diff -urN linux-2.4.18-pre7/arch/ppc/mm/pgtable.c linux/arch/ppc/mm/pgtable.c
--- linux-2.4.18-pre7/arch/ppc/mm/pgtable.c	Tue Oct  2 09:12:44 2001
+++ linux/arch/ppc/mm/pgtable.c	Mon Feb  4 12:55:44 2002
@@ -41,6 +41,11 @@
 unsigned long ioremap_bot;
 int io_bat_index;
 
+/* Maximum 768Mb of lowmem. On SMP, this value will be
+ * trimmed down to whatever can be covered by BATs though.
+ */
+#define MAX_LOW_MEM	0x30000000
+
 #ifndef CONFIG_SMP
 struct pgtable_cache_struct quicklists;
 #endif
@@ -49,6 +54,10 @@
 #define HAVE_BATS	1
 #endif
 
+#ifdef HAVE_BATS
+static unsigned long __bat2, __bat3;
+#endif
+
 extern char etext[], _stext[];
 
 #ifdef HAVE_BATS
@@ -186,6 +195,65 @@
 	return err;
 }
 
+void __init
+adjust_total_lowmem(void)
+{
+	unsigned long max_low_mem = MAX_LOW_MEM;
+	
+#ifdef HAVE_BATS
+	unsigned long bat_max = 0x10000000;
+	unsigned long align;
+	unsigned long ram = total_lowmem;
+	int is601 = 0;
+	
+	/* 601s have smaller BATs */
+	if (PVR_VER(mfspr(PVR)) == 1) {
+		bat_max = 0x00800000;
+		is601 = 1;
+	}
+
+	/* Make sure we don't map a block larger than the
+	   smallest alignment of the physical address. */
+	/* alignment of ram_phys_base */
+	align = ~(ram_phys_base-1) & ram_phys_base;
+	/* set BAT block size to MIN(max_size, align) */
+	if (align && align < bat_max)
+		bat_max = align;
+
+	/* Calculate BAT values */	
+	__bat2 = 1UL << __ilog2(ram);
+	if (__bat2 > bat_max)
+		__bat2 = bat_max;
+	ram -= __bat2;
+	if (ram) {
+		__bat3 = 1UL << __ilog2(ram);
+		if (__bat3 > bat_max)
+			__bat3 = bat_max;
+		ram -= __bat3;
+	}
+
+	printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb, residual: %ldMb\n",
+		__bat2 >> 20, __bat3 >> 20, ram >> 20);
+
+	/* On SMP, we limit the lowmem to the area mapped with BATs.
+	 * We also assume nobody will do SMP with 601s
+	 */
+#ifdef CONFIG_SMP
+	if (!is601)
+		max_low_mem = __bat2 + __bat3;
+#endif /* CONFIG_SMP */
+
+#endif /* HAVE_BATS */
+	if (total_lowmem > max_low_mem) {
+		total_lowmem = max_low_mem;
+#ifndef CONFIG_HIGHMEM
+		printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM"
+			" to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20);
+		total_memory = total_lowmem;
+#endif /* CONFIG_HIGHMEM */
+	}
+}
+
 /*
  * Map in all of physical memory starting at KERNELBASE.
  */
@@ -195,7 +263,7 @@
 
 #ifdef HAVE_BATS
 	if (!__map_without_bats)
-		bat_mapin_ram();
+		bat_mapin_ram(__bat2, __bat3);
 #endif /* HAVE_BATS */
 
 	v = KERNELBASE;
diff -urN linux-2.4.18-pre7/arch/ppc/mm/ppc_mmu.c linux/arch/ppc/mm/ppc_mmu.c
--- linux-2.4.18-pre7/arch/ppc/mm/ppc_mmu.c	Mon Nov 26 05:29:17 2001
+++ linux/arch/ppc/mm/ppc_mmu.c	Mon Feb  4 12:55:44 2002
@@ -86,37 +86,16 @@
 	return 0;
 }
 
-void __init bat_mapin_ram(void)
+void __init bat_mapin_ram(unsigned long bat2, unsigned long bat3)
 {
-	unsigned long tot, bl, done;
-	unsigned long max_size = (256<<20);
-	unsigned long align;
-
-	/* Set up BAT2 and if necessary BAT3 to cover RAM. */
-
-	/* Make sure we don't map a block larger than the
-	   smallest alignment of the physical address. */
-	/* alignment of ram_phys_base */
-	align = ~(ram_phys_base-1) & ram_phys_base;
-	/* set BAT block size to MIN(max_size, align) */
-	if (align && align < max_size)
-		max_size = align;
-
+	unsigned long tot, done;
+	
 	tot = total_lowmem;
-	for (bl = 128<<10; bl < max_size; bl <<= 1) {
-		if (bl * 2 > tot)
-			break;
-	}
-
-	setbat(2, KERNELBASE, ram_phys_base, bl, _PAGE_KERNEL);
+	setbat(2, KERNELBASE, ram_phys_base, bat2, _PAGE_KERNEL);
 	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-	if ((done < tot) && !bat_addrs[3].limit) {
-		/* use BAT3 to cover a bit more */
+	if ((done < tot) && !bat_addrs[3].limit && bat3) {
 		tot -= done;
-		for (bl = 128<<10; bl < max_size; bl <<= 1)
-			if (bl * 2 > tot)
-				break;
-		setbat(3, KERNELBASE+done, ram_phys_base+done, bl, 
+		setbat(3, KERNELBASE+done, ram_phys_base+done, bat3, 
 		       _PAGE_KERNEL);
 	}
 }
diff -urN linux-2.4.18-pre7/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- linux-2.4.18-pre7/arch/s390/kernel/time.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/s390/kernel/time.c	Mon Feb  4 12:55:44 2002
@@ -228,7 +228,4 @@
 
         /* init CPU timer */
         init_cpu_timer();
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -urN linux-2.4.18-pre7/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
--- linux-2.4.18-pre7/arch/s390x/kernel/time.c	Mon Feb  4 12:55:37 2002
+++ linux/arch/s390x/kernel/time.c	Mon Feb  4 12:55:44 2002
@@ -201,7 +201,4 @@
 
         /* init CPU timer */
         init_cpu_timer();
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -urN linux-2.4.18-pre7/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- linux-2.4.18-pre7/arch/sparc/kernel/pcic.c	Sun Feb 18 19:49:44 2001
+++ linux/arch/sparc/kernel/pcic.c	Mon Feb  4 12:55:50 2002
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
+/* $Id: pcic.c,v 1.22.2.1 2002/01/23 14:35:45 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -759,7 +759,6 @@
 	unsigned long v;
 	int timer_irq, irq;
 
-	do_get_fast_time = pci_do_gettimeofday;
 	/* A hack until do_gettimeofday prototype is moved to arch specific headers
 	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
 	((unsigned int *)do_gettimeofday)[0] = 
diff -urN linux-2.4.18-pre7/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- linux-2.4.18-pre7/arch/sparc/kernel/time.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc/kernel/time.c	Mon Feb  4 12:55:50 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.59 2001/10/30 04:54:21 davem Exp $
+/* $Id: time.c,v 1.59.2.1 2002/01/23 14:35:45 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -371,7 +371,6 @@
 	struct intersil *iregs;
 #endif
 
-	do_get_fast_time = do_gettimeofday;
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
diff -urN linux-2.4.18-pre7/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- linux-2.4.18-pre7/arch/sparc64/kernel/time.c	Fri Dec 21 09:41:53 2001
+++ linux/arch/sparc64/kernel/time.c	Mon Feb  4 12:55:50 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
+/* $Id: time.c,v 1.41.2.1 2002/01/23 14:35:45 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -329,8 +329,6 @@
 	unsigned long dregs = 0UL;
 #endif
 	u8 tmp;
-
-	do_get_fast_time = do_gettimeofday;
 
 	if (!mregs && !dregs) {
 		prom_printf("Something wrong, clock regs not mapped yet.\n");
diff -urN linux-2.4.18-pre7/drivers/Makefile linux/drivers/Makefile
--- linux-2.4.18-pre7/drivers/Makefile	Sun Nov 11 10:09:32 2001
+++ linux/drivers/Makefile	Mon Feb  4 12:55:50 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux kernel device drivers.
 #
-# 15 Sep 2000, Christoph Hellwig <hch@caldera.de>
+# 15 Sep 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/drivers/block/Makefile linux/drivers/block/Makefile
--- linux-2.4.18-pre7/drivers/block/Makefile	Sun Sep  9 12:00:55 2001
+++ linux/drivers/block/Makefile	Mon Feb  4 12:55:50 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the kernel block device drivers.
 #
-# 12 June 2000, Christoph Hellwig <schch@pe.tu-clausthal.de>
+# 12 June 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 # 
 # Note : at this point, these files are compiled on all systems.
diff -urN linux-2.4.18-pre7/drivers/block/blkpg.c linux/drivers/block/blkpg.c
--- linux-2.4.18-pre7/drivers/block/blkpg.c	Sun Nov 11 10:20:21 2001
+++ linux/drivers/block/blkpg.c	Mon Feb  4 12:55:50 2002
@@ -247,7 +247,7 @@
 			if (cmd == BLKGETSIZE)
 				return put_user((unsigned long)ullval, (unsigned long *)arg);
 			else
-				return put_user(ullval, (u64 *)arg);
+				return put_user(ullval << 9, (u64 *)arg);
 #if 0
 		case BLKRRPART: /* Re-read partition tables */
 			if (!capable(CAP_SYS_ADMIN)) 
diff -urN linux-2.4.18-pre7/drivers/char/drm/sis_drv.c linux/drivers/char/drm/sis_drv.c
--- linux-2.4.18-pre7/drivers/char/drm/sis_drv.c	Fri Dec 21 09:41:53 2001
+++ linux/drivers/char/drm/sis_drv.c	Mon Feb  4 12:55:50 2002
@@ -40,12 +40,12 @@
 #define DRIVER_PATCHLEVEL  0
 
 #define DRIVER_IOCTLS \
-        [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)]   = { sis_fb_alloc,	  1, 1 }, \
-        [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)]    = { sis_fb_free,	  1, 1 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)]   = { sis_fb_alloc,	  1, 0 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)]    = { sis_fb_free,	  1, 0 }, \
         /* AGP Memory Management */					  \
-        [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)]   = { sisp_agp_init,	  1, 1 }, \
-        [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)]  = { sisp_agp_alloc,  1, 1 }, \
-        [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)]   = { sisp_agp_free,	  1, 1 }
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)]   = { sisp_agp_init,	  1, 0 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)]  = { sisp_agp_alloc,  1, 0 }, \
+        [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)]   = { sisp_agp_free,	  1, 0 }
 #if 0 /* these don't appear to be defined */
 	/* SIS Stereo */						 
 	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]    = { sis_control,	  1, 1 }, 
diff -urN linux-2.4.18-pre7/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- linux-2.4.18-pre7/drivers/char/generic_serial.c	Thu Sep 13 15:21:32 2001
+++ linux/drivers/char/generic_serial.c	Mon Feb  4 12:55:50 2002
@@ -143,7 +143,12 @@
 		/* Can't copy more? break out! */
 		if (c <= 0) break;
 		if (from_user)
-			copy_from_user (port->xmit_buf + port->xmit_head, buf, c);
+                       if (copy_from_user (port->xmit_buf + port->xmit_head, 
+                                           buf, c)) {
+                               up (& port->port_write_sem);
+                               return -EFAULT;
+                       }
+
 		else
 			memcpy         (port->xmit_buf + port->xmit_head, buf, c);
 
@@ -214,8 +219,13 @@
 		while (1) {
 			c = count;
 
-			/* This is safe because we "OWN" the "head". Noone else can 
-			   change the "head": we own the port_write_sem. */
+			/* Note: This part can be done without
+			 * interrupt routine protection since
+			 * the interrupt routines may only modify
+			 * shared variables in safe ways, in the worst
+			 * case causing us to loop twice in the code
+			 * below. See comments below. */ 
+
 			/* Don't overrun the end of the buffer */
 			t = SERIAL_XMIT_SIZE - port->xmit_head;
 			if (t < c) c = t;
@@ -506,7 +516,7 @@
 
 void gs_shutdown_port (struct gs_port *port)
 {
-	long flags;
+	unsigned long flags;
 
 	func_enter();
 	
@@ -589,6 +599,7 @@
 	int    do_clocal = 0;
 	int    CD;
 	struct tty_struct *tty;
+	unsigned long flags;
 
 	func_enter ();
 
@@ -604,7 +615,7 @@
 	 * until it's done, and then try again.
 	 */
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-	  interruptible_sleep_on(&port->close_wait);
+		interruptible_sleep_on(&port->close_wait);
 		if (port->flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
@@ -668,10 +679,11 @@
 	add_wait_queue(&port->open_wait, &wait);
 
 	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
+	save_flags(flags);
 	cli();
 	if (!tty_hung_up_p(filp))
 		port->count--;
-	sti();
+	restore_flags(flags);
 	port->blocked_open++;
 	while (1) {
 		CD = port->rd->get_CD (port);
@@ -1003,7 +1015,8 @@
 {
 	struct serial_struct sio;
 
-	copy_from_user(&sio, sp, sizeof(struct serial_struct));
+	if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
+		return(-EFAULT);
 
 	if (!capable(CAP_SYS_ADMIN)) {
 		if ((sio.baud_base != port->baud_base) ||
@@ -1033,7 +1046,7 @@
  *      Generate the serial struct info.
  */
 
-void gs_getserial(struct gs_port *port, struct serial_struct *sp)
+int gs_getserial(struct gs_port *port, struct serial_struct *sp)
 {
 	struct serial_struct    sio;
 
@@ -1055,7 +1068,10 @@
 	if (port->rd->getserial)
 		port->rd->getserial (port, &sio);
 
-	copy_to_user(sp, &sio, sizeof(struct serial_struct));
+	if (copy_to_user(sp, &sio, sizeof(struct serial_struct)))
+		return -EFAULT;
+	return 0;
+
 }
 
 
diff -urN linux-2.4.18-pre7/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c
--- linux-2.4.18-pre7/drivers/char/rio/rio_linux.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/char/rio/rio_linux.c	Mon Feb  4 12:55:50 2002
@@ -742,7 +742,7 @@
   case TIOCGSERIAL:
     if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
                           sizeof(struct serial_struct))) == 0)
-      gs_getserial(&PortP->gs, (struct serial_struct *) arg);
+      rc = gs_getserial(&PortP->gs, (struct serial_struct *) arg);
     break;
   case TCSBRK:
     if ( PortP->State & RIO_DELETED ) {
diff -urN linux-2.4.18-pre7/drivers/char/serial_tx3912.c linux/drivers/char/serial_tx3912.c
--- linux-2.4.18-pre7/drivers/char/serial_tx3912.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/serial_tx3912.c	Mon Feb  4 12:55:50 2002
@@ -673,7 +673,7 @@
 	case TIOCGSERIAL:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
 		                      sizeof(struct serial_struct))) == 0)
-			gs_getserial(&port->gs, (struct serial_struct *) arg);
+			rc = gs_getserial(&port->gs, (struct serial_struct *) arg);
 		break;
 	case TIOCSSERIAL:
 		if ((rc = verify_area(VERIFY_READ, (void *) arg,
diff -urN linux-2.4.18-pre7/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- linux-2.4.18-pre7/drivers/char/sh-sci.c	Mon Oct 15 13:36:48 2001
+++ linux/drivers/char/sh-sci.c	Mon Feb  4 12:55:50 2002
@@ -919,7 +919,7 @@
 	case TIOCGSERIAL:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
 		                      sizeof(struct serial_struct))) == 0)
-			gs_getserial(&port->gs, (struct serial_struct *) arg);
+			rc = gs_getserial(&port->gs, (struct serial_struct *) arg);
 		break;
 	case TIOCSSERIAL:
 		if ((rc = verify_area(VERIFY_READ, (void *) arg,
diff -urN linux-2.4.18-pre7/drivers/char/sx.c linux/drivers/char/sx.c
--- linux-2.4.18-pre7/drivers/char/sx.c	Mon Feb  4 12:55:38 2002
+++ linux/drivers/char/sx.c	Mon Feb  4 12:55:50 2002
@@ -1817,7 +1817,7 @@
 	case TIOCGSERIAL:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
 		                      sizeof(struct serial_struct))) == 0)
-			gs_getserial(&port->gs, (struct serial_struct *) arg);
+			rc = gs_getserial(&port->gs, (struct serial_struct *) arg);
 		break;
 	case TIOCSSERIAL:
 		if ((rc = verify_area(VERIFY_READ, (void *) arg,
diff -urN linux-2.4.18-pre7/drivers/i2c/i2c-keywest.c linux/drivers/i2c/i2c-keywest.c
--- linux-2.4.18-pre7/drivers/i2c/i2c-keywest.c	Mon Feb  4 12:55:38 2002
+++ linux/drivers/i2c/i2c-keywest.c	Mon Feb  4 12:55:51 2002
@@ -27,10 +27,20 @@
     2001/12/15 BenH	Add support for "byte" and "quick"
                         transfers. Add i2c_xfer routine.
 
-    ToDo:
+    My understanding of the various modes supported by keywest are:
 
-    Figure out how to use combined mode on the chip      
+     - Dumb mode : not implemented, probably direct tweaking of lines
+     - Standard mode : simple i2c transaction of type
+         S Addr R/W A Data A Data ... T
+     - Standard sub mode : combined 8 bit subaddr write with data read
+         S Addr R/W A SubAddr A Data A Data ... T
+     - Combined mode : Subaddress and Data sequences appended with no stop
+         S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
 
+    Currently, this driver uses only Standard mode for i2c xfer, and
+    smbus byte & quick transfers ; and uses StandardSub mode for
+    other smbus transfers instead of combined as we need that for the
+    sound driver to be happy
 */
 
 #include <linux/module.h>
diff -urN linux-2.4.18-pre7/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- linux-2.4.18-pre7/drivers/ide/ide-pmac.c	Mon Feb  4 12:55:38 2002
+++ linux/drivers/ide/ide-pmac.c	Mon Feb  4 12:55:51 2002
@@ -75,7 +75,13 @@
 };
 
 /*
- * Timing register definitions
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/*
+ * Timing configuration register definitions
  */
 
 /* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
@@ -144,6 +150,12 @@
 #define TR_33_PIO_ACCESS_MASK		0x0000001f
 #define TR_33_PIO_ACCESS_SHIFT		0
 
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
 /* Rounded Multiword DMA timings
@@ -331,10 +343,12 @@
 		return;
 
 	if (drive->select.b.unit & 0x01)
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]);
+		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+			pmac_ide[i].timings[1]);
 	else
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]);
-	(void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE));
+		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+			pmac_ide[i].timings[0]);
+	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
 }
 
 
@@ -405,6 +419,28 @@
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
 out:
 	SELECT_MASK(HWIF(drive), drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
 	enable_irq(hwif->irq);
 	return result;
 }
@@ -830,7 +866,7 @@
 			continue;
 		}
 
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE;
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
 
 		/* XXX This is bogus. Should be fixed in the registry by checking
 		   the kind of host interrupt controller, a bit like gatwick
@@ -898,6 +934,7 @@
 		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
 		hwif->chipset = ide_pmac;
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
 #ifdef CONFIG_PMAC_PBOOK
 		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
 			hwif->noprobe = 0;
@@ -1227,10 +1264,10 @@
 			return 1;
 		/* Apple adds 60ns to wrDataSetup on reads */
 		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE),
+			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
 				pmac_ide[ix].timings[unit] + 
 				((func == ide_dma_read) ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE));
+			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
 		}
 		drive->waiting_for_dma = 1;
 		if (drive->media != ide_disk)
diff -urN linux-2.4.18-pre7/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.4.18-pre7/drivers/ieee1394/video1394.c	Fri Dec 21 09:41:54 2001
+++ linux/drivers/ieee1394/video1394.c	Mon Feb  4 12:55:51 2002
@@ -617,7 +617,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-			get_fast_time(&d->buffer_time[i]);
+			do_gettimeofday(&d->buffer_time[i]);
 		}
 	}
 	spin_unlock(&d->lock);
diff -urN linux-2.4.18-pre7/drivers/input/evdev.c linux/drivers/input/evdev.c
--- linux-2.4.18-pre7/drivers/input/evdev.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/input/evdev.c	Mon Feb  4 12:55:51 2002
@@ -67,7 +67,7 @@
 
 	while (list) {
 
-		get_fast_time(&list->buffer[list->head].time);
+		do_gettimeofday(&list->buffer[list->head].time);
 		list->buffer[list->head].type = type;
 		list->buffer[list->head].code = code;
 		list->buffer[list->head].value = value;
diff -urN linux-2.4.18-pre7/drivers/isdn/hisax/hisax_fcpcipnp.c linux/drivers/isdn/hisax/hisax_fcpcipnp.c
--- linux-2.4.18-pre7/drivers/isdn/hisax/hisax_fcpcipnp.c	Fri Dec 21 09:41:54 2001
+++ linux/drivers/isdn/hisax/hisax_fcpcipnp.c	Mon Feb  4 12:55:51 2002
@@ -20,6 +20,7 @@
  *
  * o POWER PC
  * o clean up debugging
+ * o tx_skb at PH_DEACTIVATE time
  */
 
 #include <linux/version.h>
@@ -370,9 +371,6 @@
 
 	DBG(0x40, "hdlc_fill_fifo");
 
-	if (!skb)
-		BUG();
-
 	if (skb->len == 0)
 		BUG();
 
@@ -581,14 +579,14 @@
 		adapter->write_ctrl(bcs, 5);
 		break;
 	case L1_MODE_TRANS:
-		bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
-		adapter->write_ctrl(bcs, 5);
-		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
-		adapter->write_ctrl(bcs, 1);
-		bcs->ctrl.sr.cmd = 0;
-		break;
 	case L1_MODE_HDLC:
-		bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+		bcs->rcvidx = 0;
+		bcs->tx_cnt = 0;
+		bcs->tx_skb = NULL;
+		if (mode == L1_MODE_TRANS)
+			bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+		else
+			bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
 		adapter->write_ctrl(bcs, 5);
 		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
 		adapter->write_ctrl(bcs, 1);
diff -urN linux-2.4.18-pre7/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- linux-2.4.18-pre7/drivers/macintosh/macserial.c	Mon Feb  4 12:55:38 2002
+++ linux/drivers/macintosh/macserial.c	Mon Feb  4 12:55:51 2002
@@ -60,6 +60,7 @@
 #endif
 
 #define SUPPORT_SERIAL_DMA
+#define MACSERIAL_VERSION	"2.0"
 
 /*
  * It would be nice to dynamically allocate everything that
@@ -1032,7 +1033,7 @@
 {
 	unsigned long flags;
 
-	OPNDBG("setting up ttys%d SCC...\n", info->line);
+	OPNDBG("setting up ttyS%d SCC...\n", info->line);
 
 	save_flags(flags); cli(); /* Disable interrupts */
 
@@ -1196,7 +1197,7 @@
 	int delay = 0;
 
 	if (state) {
-		PWRDBG("ttyS%02d: powering up hardware\n", info->line);
+		PWRDBG("ttyS%d: powering up hardware\n", info->line);
 		pmac_call_feature(
 			PMAC_FTR_SCC_ENABLE,
 			info->dev_node, info->port_type, 1);
@@ -1213,9 +1214,9 @@
 		/* TODO: Make that depend on a timer, don't power down
 		 * immediately
 		 */
-		PWRDBG("ttyS%02d: shutting down hardware\n", info->line);
+		PWRDBG("ttyS%d: shutting down hardware\n", info->line);
 		if (info->is_internal_modem) {
-			PWRDBG("ttyS%02d: shutting down modem\n", info->line);
+			PWRDBG("ttyS%d: shutting down modem\n", info->line);
 			pmac_call_feature(
 				PMAC_FTR_MODEM_ENABLE,
 				info->dev_node, 0, 0);
@@ -1955,7 +1956,7 @@
 		return;
 	}
 
-	OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count);
+	OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count);
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
@@ -1970,7 +1971,7 @@
 	}
 	if (--info->count < 0) {
 		printk(KERN_ERR "rs_close: bad serial port count for "
-				"ttys%d: %d\n", info->line, info->count);
+				"ttyS%d: %d\n", info->line, info->count);
 		info->count = 0;
 	}
 	if (info->count) {
@@ -2187,7 +2188,7 @@
 	 */
 	retval = 0;
 	add_wait_queue(&info->open_wait, &wait);
-	OPNDBG("block_til_ready before block: ttys%d, count = %d\n",
+	OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
 	       info->line, info->count);
 	cli();
 	if (!tty_hung_up_p(filp)) 
@@ -2222,7 +2223,7 @@
 			retval = -ERESTARTSYS;
 			break;
 		}
-		OPNDBG("block_til_ready blocking: ttys%d, count = %d\n",
+		OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n",
 		       info->line, info->count);
 		schedule();
 	}
@@ -2231,7 +2232,7 @@
 	if (!tty_hung_up_p(filp))
 		info->count++;
 	info->blocked_open--;
-	OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n",
+	OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n",
 	       info->line, info->count);
 	if (retval)
 		return retval;
@@ -2332,7 +2333,7 @@
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
-	OPNDBG("rs_open ttys%d successful...\n", info->line);
+	OPNDBG("rs_open ttyS%d successful...\n", info->line);
 	return 0;
 }
 
@@ -2340,7 +2341,7 @@
 
 static void show_serial_version(void)
 {
-	printk(KERN_INFO "PowerMac Z8530 serial driver version 2.0\n");
+	printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n");
 }
 
 /*
@@ -2436,6 +2437,62 @@
 	return 0;
 }
 
+/*
+ * /proc fs routines. TODO: Add status lines & error stats
+ */
+static inline int
+line_info(char *buf, struct mac_serial *info)
+{
+	int		ret=0;
+	unsigned char* connector;
+	int lenp;
+
+	ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq);
+
+	connector = get_property(info->dev_node, "AAPL,connector", &lenp);
+	if (connector)
+		ret+=sprintf(buf+ret," con:%s ", connector);
+	if (info->is_internal_modem) {
+		if (!connector)
+			ret+=sprintf(buf+ret," con:");
+		ret+=sprintf(buf+ret,"%s", " (internal modem)");
+	}
+	if (info->is_irda) {
+		if (!connector)
+			ret+=sprintf(buf+ret," con:");
+		ret+=sprintf(buf+ret,"%s", " (IrDA)");
+	}
+	ret+=sprintf(buf+ret,"\n");
+
+	return ret;
+}
+
+int macserial_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int l, len = 0;
+	off_t	begin = 0;
+	struct mac_serial *info;
+
+	len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n");
+	for (info = zs_chain; info && len < 4000; info = info->zs_next) {
+		l = line_info(page + len, info);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
 static void
 probe_sccs()
@@ -2578,6 +2635,7 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "macserial";
 #ifdef CONFIG_DEVFS_FS
 	serial_driver.name = "tts/%d";
 #else
@@ -2614,6 +2672,7 @@
 	serial_driver.hangup = rs_hangup;
 	serial_driver.break_ctl = rs_break;
 	serial_driver.wait_until_sent = rs_wait_until_sent;
+	serial_driver.read_proc = macserial_read_proc;
 
 	/*
 	 * The callout device is just like normal device except for
@@ -2627,6 +2686,8 @@
 #endif /* CONFIG_DEVFS_FS */
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
 
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
@@ -2698,14 +2759,6 @@
 		if (info->is_irda)
 			printk(" (IrDA)");
 		printk("\n");
-
-#ifndef CONFIG_XMON
-#ifdef CONFIG_KGDB
-		if (!info->kgdb_channel)
-#endif /* CONFIG_KGDB */
-			/* By default, disable the port */
-			set_scc_power(info, 0);
-#endif /* CONFIG_XMON */
  	}
 	tmp_buf = 0;
 
diff -urN linux-2.4.18-pre7/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- linux-2.4.18-pre7/drivers/media/video/zr36067.c	Fri Nov  9 14:01:22 2001
+++ linux/drivers/media/video/zr36067.c	Mon Feb  4 12:55:52 2002
@@ -2609,7 +2609,7 @@
 		}
 		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
 		gbuf = &zr->jpg_gbuf[frame];
-		get_fast_time(&gbuf->bs.timestamp);
+		do_gettimeofday(&gbuf->bs.timestamp);
 
 		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
 			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
diff -urN linux-2.4.18-pre7/drivers/message/i2o/i2o_core.c linux/drivers/message/i2o/i2o_core.c
--- linux-2.4.18-pre7/drivers/message/i2o/i2o_core.c	Mon Oct 22 08:39:56 2001
+++ linux/drivers/message/i2o/i2o_core.c	Mon Feb  4 12:55:52 2002
@@ -1184,7 +1184,8 @@
 	{
 		struct i2o_handler *i;
 		/* Map the message from the page frame map to kernel virtual */
-		m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame);
+		/* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */
+		m=(struct i2o_message *)bus_to_virt(mv);
 		msg=(u32*)m;
 
 		/*
diff -urN linux-2.4.18-pre7/drivers/net/fc/Makefile linux/drivers/net/fc/Makefile
--- linux-2.4.18-pre7/drivers/net/fc/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/fc/Makefile	Mon Feb  4 12:55:53 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for linux/drivers/net/fc
 #
-# 9 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# 9 Aug 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile
--- linux-2.4.18-pre7/drivers/net/hamradio/Makefile	Thu Jan  4 12:50:12 2001
+++ linux/drivers/net/hamradio/Makefile	Mon Feb  4 12:55:53 2002
@@ -7,7 +7,7 @@
 #               Joerg Reuter DL1BKE <jreuter@yaina.de>
 #
 # 20000806	Rewritten to use lists instead of if-statements.
-#		Christoph Hellwig <hch@caldera.de>
+#		Christoph Hellwig <hch@infradead.org>
 #
 
 
diff -urN linux-2.4.18-pre7/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- linux-2.4.18-pre7/drivers/net/irda/Makefile	Thu Oct 25 13:53:47 2001
+++ linux/drivers/net/irda/Makefile	Mon Feb  4 12:55:53 2002
@@ -2,7 +2,7 @@
 #
 # Makefile for the Linux IrDA infrared port device drivers.
 #
-# 9 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# 9 Aug 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- linux-2.4.18-pre7/drivers/net/irda/ali-ircc.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/irda/ali-ircc.c	Mon Feb  4 12:55:53 2002
@@ -1496,7 +1496,7 @@
 		if (mtt) 
 		{
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			/* self->stamp is set from ali_ircc_dma_receive_complete() */
@@ -1913,7 +1913,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
diff -urN linux-2.4.18-pre7/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux-2.4.18-pre7/drivers/net/irda/irda-usb.c	Fri Nov  9 14:22:17 2001
+++ linux/drivers/net/irda/irda-usb.c	Mon Feb  4 12:55:53 2002
@@ -427,7 +427,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			int diff;
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 #ifdef IU_USB_MIN_RTT
 			/* Factor in USB delays -> Get rid of udelay() that
@@ -798,7 +798,7 @@
 	 * reduce the min turn time a bit since we will know
 	 * how much time we have used for protocol processing
 	 */
-        get_fast_time(&self->stamp);
+        do_gettimeofday(&self->stamp);
 
 	/* Fix skb, and remove USB-IrDA header */
 	skb_put(skb, purb->actual_length);
diff -urN linux-2.4.18-pre7/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.4.18-pre7/drivers/net/irda/nsc-ircc.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Feb  4 12:55:53 2002
@@ -1163,7 +1163,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			if (diff < 0) 
 				diff += 1000000;
@@ -1535,7 +1535,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
diff -urN linux-2.4.18-pre7/drivers/net/sungem.c linux/drivers/net/sungem.c
--- linux-2.4.18-pre7/drivers/net/sungem.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/net/sungem.c	Mon Feb  4 12:55:54 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.44.2.2 2002/01/15 06:26:56 davem Exp $
+/* $Id: sungem.c,v 1.44.2.3 2002/01/23 15:40:01 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -10,6 +10,10 @@
  *  - Get rid of all those nasty mdelay's and replace them
  * with schedule_timeout.
  *  - Implement WOL
+ *  - Currently, forced Gb mode is only supported on bcm54xx
+ *    PHY for which I use the SPD2 bit of the control register.
+ *    On m1011 PHY, I can't force as I don't have the specs, but
+ *    I can at least detect gigabit with autoneg.
  */
 
 #include <linux/module.h>
@@ -85,7 +89,7 @@
 	BMCR_ANENABLE,			/* 0 : autoneg */
 	0,				/* 1 : 10bt half duplex */
 	BMCR_SPEED100,			/* 2 : 100bt half duplex */
-	BMCR_SPD2, /* verify this */	/* 3 : 1000bt half duplex */
+	BMCR_SPD2, /* bcm54xx only */   /* 3 : 1000bt half duplex */
 	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */
 	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */
 	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */
@@ -998,6 +1002,14 @@
 			*fd = 1;
 		if (val & (LPA_100FULL | LPA_100HALF))
 			*spd = 100;
+
+		if (gp->phy_mod == phymod_m1011) {
+			val = phy_read(gp, 0x0a);
+			if (val & 0xc00)
+				*spd = 1000;
+			if (val & 0x800)
+				*fd = 1;
+		}
 	}
 }
 
@@ -1573,6 +1585,11 @@
 			gem_init_bcm5411_phy(gp);
 			gp->gigabit_capable = 1;
 			break;
+		case 0x1410c60:
+			printk("M1011 (Marvel ?)\n");
+			gp->phy_mod = phymod_m1011;
+			gp->gigabit_capable = 1;
+			break;
 
 		case 0x18074c0:
 			printk("Lucent\n");
@@ -1585,7 +1602,7 @@
 			break;
 
 		default:
-			printk("Unknown\n");
+			printk("Unknown (Using generic mode)\n");
 			gp->phy_mod = phymod_generic;
 			break;
 		};
@@ -1656,6 +1673,12 @@
 		writel(val, gp->regs + PCS_SCTRL);
 		gp->gigabit_capable = 1;
 	}
+
+	/* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
+	if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
+	    gp->phy_mod != phymod_bcm5411)
+	    	gp->link_cntl &= ~BMCR_SPD2;
+	    
 }
 
 static void gem_init_dma(struct gem *gp)
@@ -1857,9 +1880,8 @@
 	u32 mif_cfg;
 
 	/* On Apple's sungem, we can't rely on registers as the chip
-	 * was been powered down by the firmware. We do the PHY lookup
-	 * when the interface is opened and we configure the driver
-	 * with known values.
+	 * was been powered down by the firmware. The PHY is looked
+	 * up later on.
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gp->phy_type = phy_mii_mdio0;
@@ -1984,7 +2006,8 @@
 
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
-	udelay(100);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout((21 * HZ) / 1000);
 
 	pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
 	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -2054,7 +2077,8 @@
 				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
 #endif				
 			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-		}
+		} else if (gp->phy_mod == phymod_m1011)
+			phy_write(gp, MII_BMCR, BMCR_PDOWN);
 
 		/* According to Apple, we must set the MDIO pins to this begnign
 		 * state or we may 1) eat more current, 2) damage some PHYs
diff -urN linux-2.4.18-pre7/drivers/net/sungem.h linux/drivers/net/sungem.h
--- linux-2.4.18-pre7/drivers/net/sungem.h	Mon Feb  4 12:55:39 2002
+++ linux/drivers/net/sungem.h	Mon Feb  4 12:55:54 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.10.2.1 2002/01/12 07:19:27 davem Exp $
+/* $Id: sungem.h,v 1.10.2.2 2002/01/23 15:40:02 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -941,6 +941,7 @@
 	phymod_bcm5400,
 	phymod_bcm5401,
 	phymod_bcm5411,
+	phymod_m1011,
 };
 
 enum link_state {
diff -urN linux-2.4.18-pre7/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile
--- linux-2.4.18-pre7/drivers/net/wan/Makefile	Sun Aug 12 10:38:48 2001
+++ linux/drivers/net/wan/Makefile	Mon Feb  4 12:55:54 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux network (wan) device drivers.
 #
-# 3 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# 3 Aug 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- linux-2.4.18-pre7/drivers/pnp/isapnp.c	Mon Nov 12 10:02:54 2001
+++ linux/drivers/pnp/isapnp.c	Mon Feb  4 12:55:54 2002
@@ -21,7 +21,7 @@
  *  2000-01-01	Added quirks handling for buggy hardware
  *		Peter Denison <peterd@pnd-pc.demon.co.uk>
  *  2000-06-14	Added isapnp_probe_devs() and isapnp_activate_dev()
- *		Christoph Hellwig <hch@caldera.de>
+ *		Christoph Hellwig <hch@infradead.org>
  *  2001-06-03  Added release_region calls to correspond with
  *		request_region calls when a failure occurs.  Also
  *		added KERN_* constants to printk() calls.
@@ -892,6 +892,7 @@
 		case _STAG_END:
 			if (size > 0)
 				isapnp_skip_bytes(size);
+			isapnp_config_prepare(dev);
 			return 1;
 		default:
 			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number);
diff -urN linux-2.4.18-pre7/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- linux-2.4.18-pre7/drivers/sbus/char/aurora.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/sbus/char/aurora.c	Mon Feb  4 12:55:55 2002
@@ -180,7 +180,7 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_long_delay: start\n");
 #endif
-	for (i = jiffies + delay; i > jiffies; ) ;
+	for (i = jiffies + delay; time_before(jiffies, i); ) ;
 #ifdef AURORA_DEBUG
 	printk("aurora_long_delay: end\n");
 #endif
diff -urN linux-2.4.18-pre7/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- linux-2.4.18-pre7/drivers/scsi/53c7,8xx.c	Thu Oct 25 13:53:48 2001
+++ linux/drivers/scsi/53c7,8xx.c	Mon Feb  4 12:55:55 2002
@@ -1867,7 +1867,7 @@
 	 */
 
 	timeout = jiffies + 5 * HZ / 10;
-	while ((hostdata->test_completed == -1) && jiffies < timeout) {
+	while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
 		barrier();
 		cpu_relax();
 	}
@@ -1953,7 +1953,7 @@
 	    restore_flags(flags);
 
 	    timeout = jiffies + 5 * HZ;	/* arbitrary */
-	    while ((hostdata->test_completed == -1) && jiffies < timeout) {
+	    while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
 	    	barrier();
 		cpu_relax();
 	    }
diff -urN linux-2.4.18-pre7/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- linux-2.4.18-pre7/drivers/scsi/53c7xx.c	Thu Oct 25 13:53:48 2001
+++ linux/drivers/scsi/53c7xx.c	Mon Feb  4 12:55:55 2002
@@ -1627,7 +1627,7 @@
 	 */
 
 	timeout = jiffies + 5 * HZ / 10;
-	while ((hostdata->test_completed == -1) && jiffies < timeout)
+	while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
 		barrier();
 
 	failed = 1;
@@ -1713,7 +1713,7 @@
 	    restore_flags(flags);
 
 	    timeout = jiffies + 5 * HZ;	/* arbitrary */
-	    while ((hostdata->test_completed == -1) && jiffies < timeout)
+	    while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
 	    	barrier();
 
 	    NCR53c7x0_write32 (DSA_REG, 0);
diff -urN linux-2.4.18-pre7/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux-2.4.18-pre7/drivers/scsi/Makefile	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/Makefile	Mon Feb  4 12:55:55 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for linux/drivers/scsi
 #
-# 30 May 2000, Christoph Hellwig <chhellwig@gmx.net>
+# 30 May 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 # 20 Sep 2000, Torben Mathiasen <tmm@image.dk>
diff -urN linux-2.4.18-pre7/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- linux-2.4.18-pre7/drivers/scsi/NCR5380.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/NCR5380.c	Mon Feb  4 12:55:55 2002
@@ -612,7 +612,7 @@
  *	Locks: disables irqs, takes and frees io_request_lock
  */
  
-void NCR5380_timer_fn(unsigned long unused)
+static void NCR5380_timer_fn(unsigned long unused)
 {
 	struct Scsi_Host *instance;
 
diff -urN linux-2.4.18-pre7/drivers/scsi/aacraid/README linux/drivers/scsi/aacraid/README
--- linux-2.4.18-pre7/drivers/scsi/aacraid/README	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/aacraid/README	Mon Feb  4 12:55:55 2002
@@ -25,7 +25,7 @@
 People
 -------------------------
 Alan Cox <alan@redhat.com>
-Christoph Hellwig <hch@caldera.de>	(small cleanups/fixes)
+Christoph Hellwig <hch@infradead.org>	(small cleanups/fixes)
 Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
 
 Original Driver
diff -urN linux-2.4.18-pre7/drivers/scsi/aacraid/rx.c linux/drivers/scsi/aacraid/rx.c
--- linux-2.4.18-pre7/drivers/scsi/aacraid/rx.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/aacraid/rx.c	Mon Feb  4 12:55:55 2002
@@ -199,7 +199,7 @@
 	/*
 	 *	Wait up to 30 seconds
 	 */
-	while (time_before(start+30*HZ, jiffies)) 
+	while (time_before(jiffies, start+30*HZ)) 
 	{
 		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
 		/*
diff -urN linux-2.4.18-pre7/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- linux-2.4.18-pre7/drivers/scsi/ips.c	Fri Nov  9 14:05:06 2001
+++ linux/drivers/scsi/ips.c	Mon Feb  4 12:55:55 2002
@@ -81,7 +81,7 @@
 /*            2.3.18 and later                                               */
 /*          - Sync with other changes from the 2.3 kernels                   */
 /* 4.00.06  - Fix timeout with initial FFDC command                          */
-/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@caldera.de>    */
+/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
 /* 4.10.00  - Add support for ServeRAID 4M/4L                                */
 /* 4.10.13  - Fix for dynamic unload and proc file system                    */
 /* 4.20.03  - Rename version to coincide with new release schedules          */
diff -urN linux-2.4.18-pre7/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- linux-2.4.18-pre7/drivers/scsi/megaraid.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/megaraid.c	Mon Feb  4 12:55:55 2002
@@ -1149,12 +1149,12 @@
 			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
 				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
 			} else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
 				memcpy(
 					SCpnt->sense_buffer,
 					epthru->reqsensearea, 14
 				);
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
 				/*SCpnt->result =
 					(DRIVER_SENSE << 24) |
 					(DID_ERROR << 16) | status;*/
diff -urN linux-2.4.18-pre7/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- linux-2.4.18-pre7/drivers/scsi/megaraid.h	Thu Oct 25 13:53:51 2001
+++ linux/drivers/scsi/megaraid.h	Mon Feb  4 12:55:55 2002
@@ -30,7 +30,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001\n)"
+#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001)\n"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
diff -urN linux-2.4.18-pre7/drivers/scsi/scsi_dma.c linux/drivers/scsi/scsi_dma.c
--- linux-2.4.18-pre7/drivers/scsi/scsi_dma.c	Tue Sep  5 14:08:55 2000
+++ linux/drivers/scsi/scsi_dma.c	Mon Feb  4 12:55:55 2002
@@ -259,6 +259,7 @@
 				if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
 					new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
 			} else if (SDpnt->type == TYPE_SCANNER ||
+				   SDpnt->type == TYPE_PRINTER ||
 				   SDpnt->type == TYPE_PROCESSOR ||
 				   SDpnt->type == TYPE_COMM ||
 				   SDpnt->type == TYPE_MEDIUM_CHANGER ||
diff -urN linux-2.4.18-pre7/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- linux-2.4.18-pre7/drivers/scsi/scsi_scan.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/scsi/scsi_scan.c	Mon Feb  4 12:55:55 2002
@@ -163,6 +163,7 @@
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
 	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
 	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", "*", BLIST_FORCELUN},
 
 	/*
 	 * Must be at end of list...
@@ -634,6 +635,7 @@
 	switch (type = (scsi_result[0] & 0x1f)) {
 	case TYPE_TAPE:
 	case TYPE_DISK:
+	case TYPE_PRINTER:
 	case TYPE_MOD:
 	case TYPE_PROCESSOR:
 	case TYPE_SCANNER:
diff -urN linux-2.4.18-pre7/drivers/sound/ad1848.h linux/drivers/sound/ad1848.h
--- linux-2.4.18-pre7/drivers/sound/ad1848.h	Fri Aug 11 08:26:43 2000
+++ linux/drivers/sound/ad1848.h	Mon Feb  4 12:55:55 2002
@@ -1,8 +1,3 @@
-/*
- * ad1848.c
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- */
 
 #define AD_F_CS4231     0x0001  /* Returned if a CS4232 (or compatible) detected */
 #define AD_F_CS4248     0x0001  /* Returned if a CS4248 (or compatible) detected */
diff -urN linux-2.4.18-pre7/drivers/sound/cs4232.h linux/drivers/sound/cs4232.h
--- linux-2.4.18-pre7/drivers/sound/cs4232.h	Mon Jul  2 13:56:41 2001
+++ linux/drivers/sound/cs4232.h	Mon Feb  4 12:55:55 2002
@@ -1,9 +1,3 @@
-/*
- *	cs4232.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 int probe_cs4232 (struct address_info *hw_config,int useisapnp);
 void attach_cs4232 (struct address_info *hw_config);
diff -urN linux-2.4.18-pre7/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c
--- linux-2.4.18-pre7/drivers/sound/dmasound/dmasound_awacs.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/sound/dmasound/dmasound_awacs.c	Mon Feb  4 12:55:55 2002
@@ -42,10 +42,16 @@
  *		- part way to partitioning the init() stuff
  *		- first pass at 'tumbler' stuff (not support - just an attempt
  *		  to allow the driver to load on new G4s).
+ *      01/02/2002 [0.7] - BenH
+ *	        - all sort of minor bits went in since the latest update, I
+ *	          bumped the version number for that reason
 */
 
 /* GENERAL FIXME/TODO: check that the assumptions about what is written to
    mac-io is valid for DACA & Tumbler.
+
+   This driver is in bad need of a rewrite. The dbdma code has to be split,
+   some proper device-tree parsing code has to be written, etc...
 */
 
 #include <linux/types.h>
@@ -83,8 +89,8 @@
 #include "awacs_defs.h"
 #include "dmasound.h"
 
-#define DMASOUND_AWACS_REVISION 0
-#define DMASOUND_AWACS_EDITION 6
+#define DMASOUND_AWACS_REVISION	0
+#define DMASOUND_AWACS_EDITION	7
 
 #define AWACS_BURGUNDY	100	/* fake revision # for burgundy */
 #define AWACS_TUMBLER    90	/* fake revision # for tumbler */
@@ -297,6 +303,8 @@
 extern void tumbler_get_bass(int *bass);
 extern void tumbler_set_pcm_lvl(int pcm_lvl);
 extern void tumbler_get_pcm_lvl(int *pcm_lvl);
+extern int tumbler_enter_sleep(void);
+extern int tumbler_leave_sleep(void);
 
 #define TRY_LOCK()	\
 	if ((rc = down_interruptible(&dmasound_sem)) != 0)	\
@@ -1285,7 +1293,8 @@
 		/* deny interrupts */
 		switch (awacs_revision) {
 			case AWACS_TUMBLER:
-				break ;		/* dont know how yet */
+				tumbler_enter_sleep(); /* Stub for now */
+				break ;
 			case AWACS_DACA:
 				daca_enter_sleep();
 				break ;
@@ -1328,6 +1337,7 @@
 		switch (awacs_revision) {
 			case AWACS_TUMBLER:
 				headphone_intr(0,0,0);
+				tumbler_leave_sleep(); /* Stub for now */
 				break;
 			case AWACS_DACA:
 				wait_ms(10); /* Check this !!! */
@@ -2024,7 +2034,7 @@
 		rc = IOCTL_OUT(arg, data);
 		break;
 	case SOUND_MIXER_READ_STEREODEVS:
-		data = SOUND_MASK_VOLUME;
+		data = SOUND_MASK_VOLUME | SOUND_MASK_PCM;
 		rc = IOCTL_OUT(arg, data);
 		break;
 	case SOUND_MIXER_READ_CAPS:
@@ -2033,6 +2043,7 @@
 	case SOUND_MIXER_WRITE_BASS:
 		IOCTL_IN(arg, data);
 		tumbler_set_bass(data);
+		/* Fall through */
 	case SOUND_MIXER_READ_BASS:
 		tumbler_get_bass(&data);
 		rc = IOCTL_OUT(arg, data);
@@ -2681,27 +2692,18 @@
 __init set_hw_byteswap(struct device_node *io)
 {
 	struct device_node *mio ;
-	unsigned int *p, rev = 0 ;
+	unsigned int *p, kl = 0 ;
 
-	/* if seems that Keylargo (at least rev2) can't byte-swap  */
+	/* if seems that Keylargo can't byte-swap  */
 
 	for (mio = io->parent; mio ; mio = mio->parent) {
 		if (strcmp(mio->name, "mac-io") == 0) {
-			if (device_is_compatible(mio, "Keylargo")){
-				p = (unsigned int *)
-					get_property(mio, "revision-id", 0);
-				if (p)
-					rev = *p ;
-			}
+			if (device_is_compatible(mio, "Keylargo"))
+				kl = 1;
 			break;
 		}
 	}
-	if (rev >= 2) {
-		hw_can_byteswap = 0;
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: found Keylargo rev 2 or later - H/W byte-swap disabled\n") ;
-#endif
-	}
+	hw_can_byteswap = !kl;
 }
 
 /* Allocate the resources necessary for beep generation.  This cannot be (quite)
diff -urN linux-2.4.18-pre7/drivers/sound/dmasound/dmasound_core.c linux/drivers/sound/dmasound/dmasound_core.c
--- linux-2.4.18-pre7/drivers/sound/dmasound/dmasound_core.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/sound/dmasound/dmasound_core.c	Mon Feb  4 12:55:55 2002
@@ -223,15 +223,6 @@
 static int shared_resources_initialised = 0 ;
 
     /*
-     *  Common stuff
-     */
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
-	return -ESPIPE;
-}
-
-    /*
      *  Mid level stuff
      */
 
diff -urN linux-2.4.18-pre7/drivers/sound/dmasound/tas3001c.c linux/drivers/sound/dmasound/tas3001c.c
--- linux-2.4.18-pre7/drivers/sound/dmasound/tas3001c.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/sound/dmasound/tas3001c.c	Mon Feb  4 12:55:55 2002
@@ -14,6 +14,19 @@
  *   * Enable control over input line 2 (is this connected?)
  *   * Play with the dual six-stage cascading biquad filtering to see how
  *     we can use it to our advantage (currently not implemented)
+ *   * Reorganise driver a bit to make it cleaner and easier to work with
+ *     (read: use the header file more :-P)
+ *   * Implement sleep support
+ *
+ *   Version 0.4:
+ *   ------------
+ *   * Balance control finally works (can someone document OSS better please?)
+ *   * Moved to a struct for common values referenced in the driver
+ *   * Put stubs in for sleep/wake-up support for now.  This will take some
+ *     experimentation to make sure that the timing is right, since the
+ *     TAS hardware requires specific timing while enabling low-power mode.
+ *     I may cheat for now and just reset the chip on wake-up, but I'd rather
+ *     not if I don't have to.
  *
  *   Version 0.3:
  *   ------------
@@ -47,20 +60,15 @@
 
 #define TAS_SETTING_MAX	100
 
-#define VOL_DEFAULT	(((TAS_SETTING_MAX*4)/5)<<0)
+#define VOL_DEFAULT	(((((TAS_SETTING_MAX*4)/5)<<0)<<8) | (((TAS_SETTING_MAX*4)/5)<<0))
 #define INPUT_DEFAULT	(((TAS_SETTING_MAX*4)/5)<<0)
 #define BASS_DEFAULT	((TAS_SETTING_MAX/2)<<0)
 #define TREBLE_DEFAULT	((TAS_SETTING_MAX/2)<<0)
 
-static uint cur_left_vol;
-static uint cur_right_vol;
-static uint cur_pcm_lvl;
-static uint cur_treble;
-static uint cur_bass;
-
 static struct i2c_client * tumbler_client = NULL;
 
-static int tas_attach_adapter(struct i2c_adapter *adapter);
+static int tumbler_enter_sleep(void);
+static int tumbler_leave_sleep(void);
 
 static int tas_attach_adapter(struct i2c_adapter *adapter);
 static int tas_detect_client(struct i2c_adapter *adapter, int address);
@@ -73,9 +81,12 @@
 static struct device_node* tas_node;
 static u8 tas_i2c_address = 0x34;
 
-
-struct tas_data {
-	int arf; /* place holder for future use */
+struct tas_data_t {
+	uint left_vol;		/* left volume */
+	uint right_vol;		/* right volume */
+	uint treble;		/* treble */
+	uint bass;		/* bass */
+	uint pcm_level;		/* pcm level */
 };
 
 struct i2c_driver tas_driver = {  
@@ -89,11 +100,19 @@
 	dec_use:	NULL  /* &tas_dev_use  */
 };
 
-void
+int
 tumbler_get_volume(uint * left_vol, uint  *right_vol)
 {
-	*left_vol = cur_left_vol;
-	*right_vol = cur_right_vol;
+	struct tas_data_t *data;
+
+	if (!tumbler_client)
+		return -1;
+
+	data = (struct tas_data_t *) (tumbler_client->data);
+	*left_vol = data->left_vol;
+	*right_vol = data->right_vol;
+	
+	return 0;
 }
 
 int
@@ -106,22 +125,46 @@
 	return 0;
 }
 
-void
+int
 tumbler_get_pcm_lvl(uint *pcm_lvl)
 {
-	*pcm_lvl = cur_pcm_lvl;
+	struct tas_data_t *data;
+
+	if (!tumbler_client)
+		return -1;
+
+	data = (struct tas_data_t *) (tumbler_client->data);
+	*pcm_lvl = data->pcm_level;
+
+	return 0;
 }
 
-void
+int
 tumbler_get_treble(uint *treble)
 {
-	*treble = cur_treble;
+	struct tas_data_t *data;
+
+	if (!tumbler_client)
+		return -1;
+
+	data = (struct tas_data_t *) (tumbler_client->data);
+	*treble = data->treble;
+	
+	return 0;
 }
 
-void
+int
 tumbler_get_bass(uint *bass)
 {
-	*bass = cur_bass;
+	struct tas_data_t *data;
+
+	if (!tumbler_client)
+		return -1;
+
+	data = (struct tas_data_t *) (tumbler_client->data);
+	*bass = data->bass;
+
+	return 0;
 }
 
 int
@@ -129,10 +172,13 @@
 {
 	uint cur_bass_pers = bass;
 	char block;
+	struct tas_data_t *data;
 
 	if (!tumbler_client)
 		return -1;
 
+	data = (struct tas_data_t *) (tumbler_client->data);
+
 	bass &= 0xff;
 	if (bass > TAS_SETTING_MAX)
 		bass = TAS_SETTING_MAX;
@@ -144,19 +190,22 @@
 		printk("tas3001c: failed to set bass \n");  
 		return -1; 
 	}
-	cur_bass = cur_bass_pers;
+	data->bass = cur_bass_pers;
 	return 0;
 }
-	
+
 int
 tumbler_set_treble(uint treble)
 {
 	uint cur_treble_pers = treble;
 	char block;
+	struct tas_data_t *data;
 
 	if (!tumbler_client)
 		return -1;
 
+	data = (struct tas_data_t *) (tumbler_client->data);
+
 	treble &= 0xff;
 	if (treble > TAS_SETTING_MAX)
 		treble = TAS_SETTING_MAX;
@@ -168,7 +217,7 @@
 		printk("tas3001c: failed to set treble \n");  
 		return -1; 
 	}
-	cur_treble = cur_treble_pers;
+	data->treble = cur_treble_pers;
 	return 0;
 }
 
@@ -177,10 +226,13 @@
 {
 	uint pcm_lvl_pers = pcm_lvl;
 	unsigned char block[3];
-  
+	struct tas_data_t *data;
+
 	if (!tumbler_client)
 		return -1;
 
+	data = (struct tas_data_t *) (tumbler_client->data);
+
 	pcm_lvl &= 0xff;
 	if (pcm_lvl > TAS_SETTING_MAX)
 		pcm_lvl = TAS_SETTING_MAX;
@@ -196,7 +248,7 @@
 		printk("tas3001c: failed to set input level \n");  
 		return -1; 
 	}
-	cur_pcm_lvl = pcm_lvl_pers;
+	data->pcm_level = pcm_lvl_pers;
 
 	return 0;
 }
@@ -207,16 +259,21 @@
 	uint left_vol_pers = left_vol;
 	uint right_vol_pers = right_vol;
 	unsigned char block[6];
-  
+	struct tas_data_t *data;
+
 	if (!tumbler_client)
 		return -1;
 
+	data = (struct tas_data_t *) (tumbler_client->data);
+
 	left_vol &= 0xff;
 	if (left_vol > TAS_SETTING_MAX)
 		left_vol = TAS_SETTING_MAX;
-	right_vol &= 0xff;
+
+	right_vol = (right_vol >> 8) & 0xff;
 	if (right_vol > TAS_SETTING_MAX)
 		right_vol = TAS_SETTING_MAX;
+
 	left_vol = ((left_vol * 176) / TAS_SETTING_MAX) << 0;
 	right_vol = ((right_vol * 176) / TAS_SETTING_MAX) << 0;
 
@@ -235,8 +292,28 @@
 		printk("tas3001c: failed to set volume \n");  
 		return -1; 
 	}
-	cur_left_vol = left_vol_pers;
-	cur_right_vol = right_vol_pers;
+	data->left_vol = left_vol_pers;
+	data->right_vol = right_vol_pers;
+
+	return 0;
+}
+
+static int
+tumbler_leave_sleep(void)
+{
+	/* Stub for now, but I have the details on low-power mode */
+	if (!tumbler_client)
+		return -1;
+
+	return 0;
+}
+
+static int
+tumbler_enter_sleep(void)
+{
+	/* Stub for now, but I have the details on low-power mode */
+	if (!tumbler_client)
+		return -1;
 
 	return 0;
 }
@@ -254,18 +331,18 @@
 tas_init_client(struct i2c_client * new_client)
 {
 	/* Make sure something answers on the i2c bus
-	 */
+	*/
 
 	if (i2c_smbus_write_byte_data(new_client, 1, (1<<6)+(2<<4)+(2<<2)+0) < 0)
 		return -1;
 
 	tumbler_client = new_client;
-	
+
 	tumbler_set_volume(VOL_DEFAULT, VOL_DEFAULT);
 	tumbler_set_pcm_lvl(INPUT_DEFAULT);
 	tumbler_set_bass(BASS_DEFAULT);
 	tumbler_set_treble(TREBLE_DEFAULT);
-	
+
 	return 0;
 }
 
@@ -274,21 +351,21 @@
 {
 	int rc = 0;
 	struct i2c_client *new_client;
-	struct tas_data *data;
+	struct tas_data_t *data;
 	const char *client_name = "tas 3001c Digital Equalizer";
 
 	new_client = kmalloc(
-			sizeof(struct i2c_client) + sizeof(struct tas_data),
-			GFP_KERNEL);
+			     sizeof(struct i2c_client) + sizeof(struct tas_data_t),
+			     GFP_KERNEL);
 	if (!new_client) {
 		rc = -ENOMEM;
 		goto bail;
 	}
-  
+
 	/* This is tricky, but it will set the data to the right value. */
 	new_client->data = new_client + 1;
-	data = (struct tas_data *) (new_client->data);
-  
+	data = (struct tas_data_t *) (new_client->data);
+
 	new_client->addr = address;
 	new_client->data = data;
 	new_client->adapter = adapter;
@@ -323,7 +400,7 @@
 
 	i2c_detach_client(client);
 	kfree(client);
-	
+
 	return 0;
 }
 
@@ -334,7 +411,7 @@
 		return -ENODEV;
 	i2c_del_driver(&tas_driver);
 	tas_initialized = 0;
-	
+
 	return 0;
 }
 
@@ -356,7 +433,7 @@
 	if (paddr) {
 		tas_i2c_address = (*paddr) >> 1;
 		printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
-			tas_i2c_address);
+		       tas_i2c_address);
 	} else    
 		printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address);
 
diff -urN linux-2.4.18-pre7/drivers/sound/gus.h linux/drivers/sound/gus.h
--- linux-2.4.18-pre7/drivers/sound/gus.h	Mon Dec 11 13:15:23 2000
+++ linux/drivers/sound/gus.h	Mon Feb  4 12:55:55 2002
@@ -1,9 +1,3 @@
-/*
- * gus.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 #include "ad1848.h"
 
diff -urN linux-2.4.18-pre7/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.4.18-pre7/drivers/sound/i810_audio.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/sound/i810_audio.c	Mon Feb  4 12:55:55 2002
@@ -14,7 +14,7 @@
  *	Analog Devices (A major AC97 codec maker)
  *	Intel Corp  (you've probably heard of them already)
  *
- * AC97 clues and assistance provided by
+ *  AC97 clues and assistance provided by
  *	Analog Devices
  *	Zach 'Fufu' Brown
  *	Jeff Garzik
@@ -63,6 +63,8 @@
  *	This is available via the 'ftsodell=1' option. 
  *
  *	If you need to force a specific rate set the clocking= option
+ *
+ *	This driver is cursed. (Ben LaHaise)
  */
  
 #include <linux/module.h>
@@ -102,15 +104,22 @@
 #ifndef PCI_DEVICE_ID_INTEL_440MX
 #define PCI_DEVICE_ID_INTEL_440MX	0x7195
 #endif
+#ifndef PCI_DEVICE_ID_SI_7012
+#define PCI_DEVICE_ID_SI_7012		0x7012
+#endif
+#ifndef PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO	0x01b1
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
-static unsigned int clocking=48000;
+static unsigned int clocking=0;
 static int spdif_locked=0;
 
 //#define DEBUG
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
+//#define DEBUG_MMAP
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -197,7 +206,7 @@
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
 
-#define DRIVER_VERSION "0.04"
+#define DRIVER_VERSION "0.21"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -220,7 +229,9 @@
 	ICH82901AB,
 	INTEL440MX,
 	INTELICH2,
-	INTELICH3
+	INTELICH3,
+	SI7012,
+	NVIDIA_NFORCE
 };
 
 static char * card_names[] = {
@@ -228,7 +239,9 @@
 	"Intel ICH 82901AB",
 	"Intel 440MX",
 	"Intel ICH2",
-	"Intel ICH3"
+	"Intel ICH3",
+	"SiS 7012",
+	"NVIDIA nForce Audio"
 };
 
 static struct pci_device_id i810_pci_tbl [] __initdata = {
@@ -242,6 +255,10 @@
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH3,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
 	{0,}
 };
 
@@ -357,39 +374,17 @@
 	struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
 	struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
 	void (*free_pcm_channel)(struct i810_card *, int chan);
+
+	/* We have a *very* long init time possibly, so use this to block */
+	/* attempts to open our devices before we are ready (stops oops'es) */
+	int initializing;
 };
 
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
-				unsigned long arg);
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
+static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
+			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
 
@@ -606,9 +601,8 @@
 		rate = 8000;
 		dmabuf->rate = (rate * 48000)/clocking;
 	}
-	
-	new_rate = ac97_set_dac_rate(codec, rate);
 
+        new_rate=ac97_set_dac_rate(codec, rate);
 	if(new_rate != rate) {
 		dmabuf->rate = (new_rate * 48000)/clocking;
 	}
@@ -666,47 +660,49 @@
 static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned int civ, offset;
-	struct i810_channel *c;
+	unsigned int civ, offset, port, port_picb, bytes = 2;
 	
 	if (!dmabuf->enable)
 		return 0;
+
 	if (rec)
-		c = dmabuf->read_channel;
+		port = state->card->iobase + dmabuf->read_channel->port;
 	else
-		c = dmabuf->write_channel;
+		port = state->card->iobase + dmabuf->write_channel->port;
+
+	if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
+		port_picb = port + OFF_SR;
+		bytes = 1;
+	} else
+		port_picb = port + OFF_PICB;
+
 	do {
-		civ = inb(state->card->iobase+c->port+OFF_CIV);
-		offset = (civ + 1) * dmabuf->fragsize -
-			      2 * inw(state->card->iobase+c->port+OFF_PICB);
-		/* CIV changed before we read PICB (very seldom) ?
-		 * then PICB was rubbish, so try again */
-	} while (civ != inb(state->card->iobase+c->port+OFF_CIV));
+		civ = inb(port+OFF_CIV) & 31;
+		offset = inw(port_picb);
+		/* Must have a delay here! */ 
+		if(offset == 0)
+			udelay(1);
+		/* Reread both registers and make sure that that total
+		 * offset from the first reading to the second is 0.
+		 * There is an issue with SiS hardware where it will count
+		 * picb down to 0, then update civ to the next value,
+		 * then set the new picb to fragsize bytes.  We can catch
+		 * it between the civ update and the picb update, making
+		 * it look as though we are 1 fragsize ahead of where we
+		 * are.  The next to we get the address though, it will
+		 * be back in the right place, and we will suddenly think
+		 * we just went forward dmasize - fragsize bytes, causing
+		 * totally stupid *huge* dma overrun messages.  We are
+		 * assuming that the 1us delay is more than long enough
+		 * that we won't have to worry about the chip still being
+		 * out of sync with reality ;-)
+		 */
+	} while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb));
 		 
-	return offset;
+	return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
+		% dmabuf->dmasize);
 }
 
-//static void resync_dma_ptrs(struct i810_state *state, int rec)
-//{
-//	struct dmabuf *dmabuf = &state->dmabuf;
-//	struct i810_channel *c;
-//	int offset;
-//
-//	if(rec) {
-//		c = dmabuf->read_channel;
-//	} else {
-//		c = dmabuf->write_channel;
-//	}
-//	if(c==NULL)
-//		return;
-//	offset = inb(state->card->iobase+c->port+OFF_CIV);
-//	if(offset == inb(state->card->iobase+c->port+OFF_LVI))
-//		offset++;
-//	offset *= dmabuf->fragsize;
-//	
-//	dmabuf->hwptr=dmabuf->swptr = offset;
-//}
-	
 /* Stop recording (lock held) */
 static inline void __stop_adc(struct i810_state *state)
 {
@@ -718,7 +714,10 @@
 	// wait for the card to acknowledge shutdown
 	while( inb(card->iobase + PI_CR) != 0 ) ;
 	// now clear any latent interrupt bits (like the halt bit)
-	outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );
+	if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+		outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB );
+	else
+		outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );
 	outl( inl(card->iobase + GLOB_STA) & INT_PI, card->iobase + GLOB_STA);
 }
 
@@ -732,21 +731,27 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }
 
-static void start_adc(struct i810_state *state)
+static inline void __start_adc(struct i810_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_card *card = state->card;
-	unsigned long flags;
 
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, card->iobase + PI_CR);
-		spin_unlock_irqrestore(&card->lock, flags);
+		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
 	}
 }
 
+static void start_adc(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
 /* stop playback (lock held) */
 static inline void __stop_dac(struct i810_state *state)
 {
@@ -758,7 +763,10 @@
 	// wait for the card to acknowledge shutdown
 	while( inb(card->iobase + PO_CR) != 0 ) ;
 	// now clear any latent interrupt bits (like the halt bit)
-	outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );
+	if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+		outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB );
+	else
+		outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );
 	outl( inl(card->iobase + GLOB_STA) & INT_PO, card->iobase + GLOB_STA);
 }
 
@@ -772,20 +780,25 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }	
 
-static void start_dac(struct i810_state *state)
+static inline void __start_dac(struct i810_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_card *card = state->card;
-	unsigned long flags;
 
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-		spin_lock_irqsave(&card->lock, flags);
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, card->iobase + PO_CR);
-		spin_unlock_irqrestore(&card->lock, flags);
+		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
 	}
 }
+static void start_dac(struct i810_state *state)
+{
+	struct i810_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__start_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
 
 #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
@@ -805,6 +818,8 @@
 		dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
 	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
 
+	if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
+		return 0;
 	/* alloc enough to satisfy the oss params */
 	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
 		if ( (PAGE_SIZE<<order) > size )
@@ -873,14 +888,19 @@
 	dmabuf->swptr = dmabuf->hwptr = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
-	/* allocate DMA buffer if not allocated yet */
-	if (dmabuf->rawbuf)
-		dealloc_dmabuf(state);
+	/* allocate DMA buffer, let alloc_dmabuf determine if we are already
+	 * allocated well enough or if we should replace the current buffer
+	 * (assuming one is already allocated, if it isn't, then allocate it).
+	 */
 	if ((ret = alloc_dmabuf(state)))
 		return ret;
 
 	/* FIXME: figure out all this OSS fragment stuff */
 	/* I did, it now does what it should according to the OSS API.  DL */
+	/* We may not have realloced our dmabuf, but the fragment size to
+	 * fragment number ratio may have changed, so go ahead and reprogram
+	 * things
+	 */
 	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
 	dmabuf->numfrag = SG_LEN;
 	dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
@@ -922,6 +942,8 @@
 			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
+			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
+				sg->control <<= 1;
 			sg->control|=CON_BUFPAD;
 			// set us up to get IOC interrupts as often as needed to
 			// satisfy numfrag requirements, no more
@@ -935,7 +957,6 @@
 		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
 		outb(0, state->card->iobase+c->port+OFF_CIV);
 		outb(0, state->card->iobase+c->port+OFF_LVI);
-		dmabuf->count = 0;
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -969,31 +990,34 @@
 	else
 		port += dmabuf->write_channel->port;
 
-	if(dmabuf->mapped) {
-		if(rec)
-			dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize
-				       	- dmabuf->count) % dmabuf->dmasize;
-		else
-			dmabuf->swptr = (dmabuf->hwptr + dmabuf->count)
-			       		% dmabuf->dmasize;
-	}
-	/*
-	 * two special cases, count == 0 on write
-	 * means no data, and count == dmasize
-	 * means no data on read, handle appropriately
+	/* if we are currently stopped, then our CIV is actually set to our
+	 * *last* sg segment and we are ready to wrap to the next.  However,
+	 * if we set our LVI to the last sg segment, then it won't wrap to
+	 * the next sg segment, it won't even get a start.  So, instead, when
+	 * we are stopped, we set both the LVI value and also we increment
+	 * the CIV value to the next sg segment to be played so that when
+	 * we call start_{dac,adc}, things will operate properly
 	 */
-	if(!rec && dmabuf->count == 0) {
-		outb(inb(port+OFF_CIV),port+OFF_LVI);
-		return;
-	}
-	if(rec && dmabuf->count == dmabuf->dmasize) {
-		outb(inb(port+OFF_CIV),port+OFF_LVI);
-		return;
+	if (!dmabuf->enable && dmabuf->ready) {
+		if(rec && dmabuf->count < dmabuf->dmasize &&
+		   (dmabuf->trigger & PCM_ENABLE_INPUT))
+		{
+			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			__start_adc(state);
+			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
+		} else if (!rec && dmabuf->count &&
+			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
+		{
+			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			__start_dac(state);
+			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
+		}
 	}
+
 	/* swptr - 1 is the tail of our transfer */
 	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
 	x /= dmabuf->fragsize;
-	outb(x&31, port+OFF_LVI);
+	outb(x, port+OFF_LVI);
 }
 
 static void i810_update_lvi(struct i810_state *state, int rec)
@@ -1020,7 +1044,9 @@
 		/* update hardware pointer */
 		hwptr = i810_get_dma_addr(state, 1);
 		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
 		dmabuf->hwptr = hwptr;
 		dmabuf->total_bytes += diff;
 		dmabuf->count += diff;
@@ -1029,8 +1055,8 @@
 			/* this is normal for the end of a read */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if(inb(state->card->iobase + PI_CIV) !=
-			   inb(state->card->iobase + PI_LVI)) {
+			if((inb(state->card->iobase + PI_CIV) & 31) !=
+			   (inb(state->card->iobase + PI_LVI) & 31)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
 				dmabuf->error++;
 			}
@@ -1043,7 +1069,9 @@
 		/* update hardware pointer */
 		hwptr = i810_get_dma_addr(state, 0);
 		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-//		printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
+		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
 		dmabuf->hwptr = hwptr;
 		dmabuf->total_bytes += diff;
 		dmabuf->count -= diff;
@@ -1052,13 +1080,13 @@
 			/* this is normal for the end of a write */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if(inb(state->card->iobase + PO_CIV) !=
-			   inb(state->card->iobase + PO_LVI)) {
+			if((inb(state->card->iobase + PO_CIV) & 31) !=
+			   (inb(state->card->iobase + PO_LVI) & 31)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
 				printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
 					"count %d\n",
-					inb(state->card->iobase + PO_CIV),
-					inb(state->card->iobase + PO_LVI),
+					inb(state->card->iobase + PO_CIV) & 31,
+					inb(state->card->iobase + PO_LVI) & 31,
 					dmabuf->hwptr, dmabuf->count);
 				dmabuf->error++;
 			}
@@ -1068,7 +1096,43 @@
 	}
 }
 
-static int drain_dac(struct i810_state *state, int nonblock)
+static inline int i810_get_free_write_space(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int free;
+
+	i810_update_ptr(state);
+	// catch underruns during playback
+	if (dmabuf->count < 0) {
+		dmabuf->count = 0;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	free = dmabuf->dmasize - dmabuf->count;
+	free -= (dmabuf->hwptr % dmabuf->fragsize);
+	if(free < 0)
+		return(0);
+	return(free);
+}
+
+static inline int i810_get_available_read_data(struct i810_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int avail;
+
+	i810_update_ptr(state);
+	// catch overruns during record
+	if (dmabuf->count > dmabuf->dmasize) {
+		dmabuf->count = dmabuf->dmasize;
+		dmabuf->swptr = dmabuf->hwptr;
+	}
+	avail = dmabuf->count;
+	avail -= (dmabuf->hwptr % dmabuf->fragsize);
+	if(avail < 0)
+		return(0);
+	return(avail);
+}
+
+static int drain_dac(struct i810_state *state, int signals_allowed)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
@@ -1078,12 +1142,12 @@
 
 	if (!dmabuf->ready)
 		return 0;
-
+	if(dmabuf->mapped) {
+		stop_dac(state);
+		return 0;
+	}
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
-		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
-		   every time to make the process really go to sleep */
-		set_current_state(TASK_INTERRUPTIBLE);
 
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
@@ -1093,33 +1157,46 @@
 		if (count <= 0)
 			break;
 
-		if (signal_pending(current))
-			break;
-
-		i810_update_lvi(state,0);
-		if (dmabuf->enable != DAC_RUNNING)
-			start_dac(state);
-
-		if (nonblock) {
-			remove_wait_queue(&dmabuf->wait, &wait);
-			set_current_state(TASK_RUNNING);
-			return -EBUSY;
+		/* 
+		 * This will make sure that our LVI is correct, that our
+		 * pointer is updated, and that the DAC is running.  We
+		 * have to force the setting of dmabuf->trigger to avoid
+		 * any possible deadlocks.
+		 */
+		if(!dmabuf->enable) {
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
+			i810_update_lvi(state,0);
 		}
+                if (signal_pending(current) && signals_allowed) {
+                        break;
+                }
 
-		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
-		tmo >>= 1;
-		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+		/* It seems that we have to set the current state to
+		 * TASK_INTERRUPTIBLE every time to make the process
+		 * really go to sleep.  This also has to be *after* the
+		 * update_ptr() call because update_ptr is likely to
+		 * do a wake_up() which will unset this before we ever
+		 * try to sleep, resuling in a tight loop in this code
+		 * instead of actually sleeping and waiting for an
+		 * interrupt to wake us up!
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		/*
+		 * set the timeout to significantly longer than it *should*
+		 * take for the DAC to drain the DMA buffer
+		 */
+		tmo = (count * HZ) / (dmabuf->rate);
+		if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
 			printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
+			count = 0;
 			break;
 		}
 	}
-	stop_dac(state);
-	synchronize_irq();
-	remove_wait_queue(&dmabuf->wait, &wait);
 	set_current_state(TASK_RUNNING);
-	if (signal_pending(current))
+	remove_wait_queue(&dmabuf->wait, &wait);
+	if(count > 0 && signal_pending(current) && signals_allowed)
 		return -ERESTARTSYS;
-
+	stop_dac(state);
 	return 0;
 }
 
@@ -1143,52 +1220,72 @@
 		if(!state->dmabuf.ready)
 			continue;
 		dmabuf = &state->dmabuf;
-		if(dmabuf->enable & DAC_RUNNING)
+		if(dmabuf->enable & DAC_RUNNING) {
 			c=dmabuf->write_channel;
-		else if(dmabuf->enable & ADC_RUNNING)
+		} else if(dmabuf->enable & ADC_RUNNING) {
 			c=dmabuf->read_channel;
-		else	/* This can occur going from R/W to close */
+		} else	/* This can occur going from R/W to close */
 			continue;
 		
 		port+=c->port;
-		
-		status = inw(port + OFF_SR);
+
+		if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+			status = inw(port + OFF_PICB);
+		else
+			status = inw(port + OFF_SR);
+
 #ifdef DEBUG_INTERRUPTS
 		printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
 #endif
 		if(status & DMA_INT_COMPLETE)
 		{
+			/* only wake_up() waiters if this interrupt signals
+			 * us being beyond a userfragsize of data open or
+			 * available, and i810_update_ptr() does that for
+			 * us
+			 */
 			i810_update_ptr(state);
 #ifdef DEBUG_INTERRUPTS
 			printk("COMP %d ", dmabuf->hwptr /
 					dmabuf->fragsize);
 #endif
 		}
-		if(status & DMA_INT_LVI)
+		if(status & (DMA_INT_LVI | DMA_INT_DCH))
 		{
+			/* wake_up() unconditionally on LVI and DCH */
 			i810_update_ptr(state);
 			wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
-			printk("LVI ");
+			if(status & DMA_INT_LVI)
+				printk("LVI ");
+			if(status & DMA_INT_DCH)
+				printk("DCH -");
 #endif
-		}
-		if(status & DMA_INT_DCH)
-		{
-			i810_update_ptr(state);
 			if(dmabuf->enable & DAC_RUNNING)
 				count = dmabuf->count;
 			else
 				count = dmabuf->dmasize - dmabuf->count;
 			if(count > 0) {
 				outb(inb(port+OFF_CR) | 1, port+OFF_CR);
+#ifdef DEBUG_INTERRUPTS
+				printk(" CONTINUE ");
+#endif
 			} else {
+				if (dmabuf->enable & DAC_RUNNING)
+					__stop_dac(state);
+				if (dmabuf->enable & ADC_RUNNING)
+					__stop_adc(state);
+				dmabuf->enable = 0;
 				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
-				printk("DCH - STOP ");
+				printk(" STOP ");
 #endif
 			}
 		}
-		outw(status & DMA_INT_MASK, port + OFF_SR);
+		if(card->pci_id == PCI_DEVICE_ID_SI_7012)
+			outw(status & DMA_INT_MASK, port + OFF_PICB);
+		else
+			outw(status & DMA_INT_MASK, port + OFF_SR);
 	}
 #ifdef DEBUG_INTERRUPTS
 	printk(")\n");
@@ -1254,15 +1351,14 @@
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	dmabuf->trigger &= ~PCM_ENABLE_OUTPUT;
 	ret = 0;
 
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&card->lock, flags);
                 if (PM_SUSPENDED(card)) {
                         spin_unlock_irqrestore(&card->lock, flags);
-                        set_current_state(TASK_INTERRUPTIBLE);
                         schedule();
                         if (signal_pending(current)) {
                                 if (!ret) ret = -EAGAIN;
@@ -1271,10 +1367,7 @@
                         continue;
                 }
 		swptr = dmabuf->swptr;
-		if (dmabuf->count > dmabuf->dmasize) {
-			dmabuf->count = dmabuf->dmasize;
-		}
-		cnt = dmabuf->count - dmabuf->fragsize;
+		cnt = i810_get_available_read_data(state);
 		// this is to make the copy_to_user simpler below
 		if(cnt > (dmabuf->dmasize - swptr))
 			cnt = dmabuf->dmasize - swptr;
@@ -1282,20 +1375,39 @@
 
 		if (cnt > count)
 			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
-			if(!dmabuf->enable) {
-				dmabuf->trigger |= PCM_ENABLE_INPUT;
-				start_adc(state);
-			}
+			/*
+			 * Don't let us deadlock.  The ADC won't start if
+			 * dmabuf->trigger isn't set.  A call to SETTRIGGER
+			 * could have turned it off after we set it to on
+			 * previously.
+			 */
+			dmabuf->trigger = PCM_ENABLE_INPUT;
+			/*
+			 * This does three things.  Updates LVI to be correct,
+			 * makes sure the ADC is running, and updates the
+			 * hwptr.
+			 */
 			i810_update_lvi(state,1);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
-				return ret;
+				goto done;
 			}
-			/* This isnt strictly right for the 810  but it'll do */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= 1;
+			/* Set the timeout to how long it would take to fill
+			 * two of our buffers.  If we haven't been woke up
+			 * by then, then we know something is wrong.
+			 */
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1303,7 +1415,7 @@
 			   is TOO LATE for the process to be scheduled to run (scheduler latency)
 			   which results in a (potential) buffer overrun. And worse, there is
 			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
 #ifdef DEBUG
 				printk(KERN_ERR "i810_audio: recording schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
@@ -1315,7 +1427,7 @@
 			}
 			if (signal_pending(current)) {
 				ret = ret ? ret : -ERESTARTSYS;
-				return ret;
+				goto done;
 			}
 			continue;
 		}
@@ -1341,10 +1453,8 @@
 		buffer += cnt;
 		ret += cnt;
 	}
-	i810_update_lvi(state,1);
-	if(!(dmabuf->enable & ADC_RUNNING))
-		start_adc(state);
  done:
+	i810_update_lvi(state,1);
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -1384,15 +1494,14 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	dmabuf->trigger &= ~PCM_ENABLE_INPUT;
 	ret = 0;
 
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&state->card->lock, flags);
                 if (PM_SUSPENDED(card)) {
                         spin_unlock_irqrestore(&card->lock, flags);
-                        set_current_state(TASK_INTERRUPTIBLE);
                         schedule();
                         if (signal_pending(current)) {
                                 if (!ret) ret = -EAGAIN;
@@ -1402,12 +1511,14 @@
                 }
 
 		swptr = dmabuf->swptr;
-		if (dmabuf->count < 0) {
-			dmabuf->count = 0;
-		}
-		cnt = dmabuf->dmasize - swptr;
-		if(cnt > (dmabuf->dmasize - dmabuf->count))
-			cnt = dmabuf->dmasize - dmabuf->count;
+		cnt = i810_get_free_write_space(state);
+		/* Bound the maximum size to how much we can copy to the
+		 * dma buffer before we hit the end.  If we have more to
+		 * copy then it will get done in a second pass of this
+		 * loop starting from the beginning of the buffer.
+		 */
+		if(cnt > (dmabuf->dmasize - swptr))
+			cnt = dmabuf->dmasize - swptr;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 #ifdef DEBUG2
@@ -1415,22 +1526,30 @@
 #endif
 		if (cnt > count)
 			cnt = count;
+		/* Lop off the last two bits to force the code to always
+		 * write in full samples.  This keeps software that sets
+		 * O_NONBLOCK but doesn't check the return value of the
+		 * write call from getting things out of state where they
+		 * think a full 4 byte sample was written when really only
+		 * a portion was, resulting in odd sound and stereo
+		 * hysteresis.
+		 */
+		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
 			// There is data waiting to be played
+			/*
+			 * Force the trigger setting since we would
+			 * deadlock with it set any other way
+			 */
+			dmabuf->trigger = PCM_ENABLE_OUTPUT;
 			i810_update_lvi(state,0);
-			if(!dmabuf->enable && dmabuf->count) {
-				/* force the starting incase SETTRIGGER has been used */
-				/* to stop it, otherwise this is a deadlock situation */
-				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
-				start_dac(state);
-			}
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				goto ret;
 			}
 			/* Not strictly correct but works */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4);
+			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1438,7 +1557,7 @@
 			   is TOO LATE for the process to be scheduled to run (scheduler latency)
 			   which results in a (potential) buffer underrun. And worse, there is
 			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
 #ifdef DEBUG
 				printk(KERN_ERR "i810_audio: playback schedule timeout, "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
@@ -1480,10 +1599,8 @@
 		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
 		memset(dmabuf->rawbuf + swptr, '\0', x);
 	}
+ret:
 	i810_update_lvi(state,0);
-	if (!dmabuf->enable && dmabuf->count >= dmabuf->userfragsize)
-		start_dac(state);
- ret:
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -1502,22 +1619,19 @@
 		return 0;
 	poll_wait(file, &dmabuf->wait, wait);
 	spin_lock_irqsave(&state->card->lock, flags);
-	i810_update_ptr(state);
-	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
-		if (dmabuf->count >= (signed)dmabuf->fragsize)
+	if (dmabuf->enable & ADC_RUNNING ||
+	    dmabuf->trigger & PCM_ENABLE_INPUT) {
+		if (i810_get_available_read_data(state) >= 
+		    (signed)dmabuf->userfragsize)
 			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) {
-		if (dmabuf->mapped) {
-			if (dmabuf->count >= (signed)dmabuf->fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
+	if (dmabuf->enable & DAC_RUNNING ||
+	    dmabuf->trigger & PCM_ENABLE_OUTPUT) {
+		if (i810_get_free_write_space(state) >=
+		    (signed)dmabuf->userfragsize)
+			mask |= POLLOUT | POLLWRNORM;
 	}
 	spin_unlock_irqrestore(&state->card->lock, flags);
-
 	return mask;
 }
 
@@ -1559,12 +1673,9 @@
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
-	if(vma->vm_flags & VM_WRITE)
-		dmabuf->count = dmabuf->dmasize;
-	else
-		dmabuf->count = 0;
+	dmabuf->trigger = 0;
 	ret = 0;
-#ifdef DEBUG
+#ifdef DEBUG_MMAP
 	printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
 #endif
 out:
@@ -1575,16 +1686,15 @@
 static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct i810_state *state = (struct i810_state *)file->private_data;
+	struct i810_channel *c = NULL;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
 	unsigned int i_glob_cnt;
-	int val = 0, mapped, ret;
+	int val = 0, ret;
 	struct ac97_codec *codec = state->card->ac97_codec[0];
 
-	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
-		((file->f_mode & FMODE_READ) && dmabuf->mapped);
 #ifdef DEBUG
 	printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0);
 #endif
@@ -1601,13 +1711,23 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_RESET\n");
 #endif
-		/* FIXME: spin_lock ? */
+		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->enable == DAC_RUNNING) {
-			stop_dac(state);
+			c = dmabuf->write_channel;
+			__stop_dac(state);
 		}
 		if (dmabuf->enable == ADC_RUNNING) {
-			stop_adc(state);
+			c = dmabuf->read_channel;
+			__stop_adc(state);
 		}
+		if (c != NULL) {
+			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
+			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
+			outb(0, state->card->iobase+c->port+OFF_CIV);
+			outb(0, state->card->iobase+c->port+OFF_LVI);
+		}
+
+		spin_unlock_irqrestore(&state->card->lock, flags);
 		synchronize_irq();
 		dmabuf->ready = 0;
 		dmabuf->swptr = dmabuf->hwptr = 0;
@@ -1620,10 +1740,9 @@
 #endif
 		if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
 			return 0;
-		drain_dac(state, 0);
-		dmabuf->ready = 0;
-		dmabuf->swptr = dmabuf->hwptr = 0;
-		dmabuf->count = dmabuf->total_bytes = 0;
+		if((val = drain_dac(state, 1)))
+			return val;
+		dmabuf->total_bytes = 0;
 		return 0;
 
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
@@ -1674,9 +1793,6 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_STEREO\n");
 #endif
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
 		if (dmabuf->enable & DAC_RUNNING) {
 			stop_dac(state);
 		}
@@ -1709,18 +1825,7 @@
 #ifdef DEBUG
 		printk("SNDCTL_DSP_SETFMT\n");
 #endif
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
-		switch ( val ) {
-			case AFMT_S16_LE:
-				break;
-			case AFMT_QUERY:
-			default:
-				val = AFMT_S16_LE;
-				break;
-		}
-		return put_user(val, (int *)arg);
+		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_CHANNELS:
 #ifdef DEBUG
@@ -1820,22 +1925,47 @@
 
 		dmabuf->ossfragsize = 1<<(val & 0xffff);
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		if (dmabuf->ossmaxfrags <= 4)
-			dmabuf->ossmaxfrags = 4;
-		else if (dmabuf->ossmaxfrags <= 8)
-			dmabuf->ossmaxfrags = 8;
-		else if (dmabuf->ossmaxfrags <= 16)
-			dmabuf->ossmaxfrags = 16;
-		else
-			dmabuf->ossmaxfrags = 32;
+		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+			return -EINVAL;
+		/*
+		 * Bound the frag size into our allowed range of 256 - 4096
+		 */
+		if (dmabuf->ossfragsize < 256)
+			dmabuf->ossfragsize = 256;
+		else if (dmabuf->ossfragsize > 4096)
+			dmabuf->ossfragsize = 4096;
+		/*
+		 * The numfrags could be something reasonable, or it could
+		 * be 0xffff meaning "Give me as much as possible".  So,
+		 * we check the numfrags * fragsize doesn't exceed our
+		 * 64k buffer limit, nor is it less than our 8k minimum.
+		 * If it fails either one of these checks, then adjust the
+		 * number of fragments, not the size of them.  It's OK if
+		 * our number of fragments doesn't equal 32 or anything
+		 * like our hardware based number now since we are using
+		 * a different frag count for the hardware.  Before we get
+		 * into this though, bound the maxfrags to avoid overflow
+		 * issues.  A reasonable bound would be 64k / 256 since our
+		 * maximum buffer size is 64k and our minimum frag size is
+		 * 256.  On the other end, our minimum buffer size is 8k and
+		 * our maximum frag size is 4k, so the lower bound should
+		 * be 2.
+		 */
+
+		if(dmabuf->ossmaxfrags > 256)
+			dmabuf->ossmaxfrags = 256;
+		else if (dmabuf->ossmaxfrags < 2)
+			dmabuf->ossmaxfrags = 2;
+
 		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-		if (val < 16384)
-			val = 16384;
-		if (val > 65536)
-			val = 65536;
-		dmabuf->ossmaxfrags = val/dmabuf->ossfragsize;
-		if(dmabuf->ossmaxfrags<4)
-			dmabuf->ossfragsize = val/4;
+		while (val < 8192) {
+		    val <<= 1;
+		    dmabuf->ossmaxfrags <<= 1;
+		}
+		while (val > 65536) {
+		    val >>= 1;
+		    dmabuf->ossmaxfrags >>= 1;
+		}
 		dmabuf->ready = 0;
 #ifdef DEBUG
 		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
@@ -1853,13 +1983,13 @@
 		i810_update_ptr(state);
 		abinfo.fragsize = dmabuf->userfragsize;
 		abinfo.fragstotal = dmabuf->userfrags;
-		if(dmabuf->mapped)
-			abinfo.bytes = dmabuf->count;
-		else
-			abinfo.bytes = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
+		if (dmabuf->mapped)
+ 			abinfo.bytes = dmabuf->dmasize;
+  		else
+ 			abinfo.bytes = i810_get_free_write_space(state);
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
 			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
 #endif
@@ -1871,17 +2001,17 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		val = i810_get_free_write_space(state);
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.ptr = dmabuf->hwptr;
-		cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->userfragsize;
-		if (dmabuf->mapped) {
-			dmabuf->count = (dmabuf->dmasize - 
-					 (dmabuf->count & (dmabuf->userfragsize-1)));
+		cinfo.blocks = val/dmabuf->userfragsize;
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
+			dmabuf->count += val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
 			__i810_update_lvi(state, 0);
 		}
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
 			cinfo.blocks, cinfo.ptr, dmabuf->count);
 #endif
@@ -1893,13 +2023,12 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		abinfo.bytes = i810_get_available_read_data(state);
 		abinfo.fragsize = dmabuf->userfragsize;
 		abinfo.fragstotal = dmabuf->userfrags;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
 		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
 			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
 #endif
@@ -1911,16 +2040,17 @@
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
-		i810_update_ptr(state);
+		val = i810_get_available_read_data(state);
 		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count/dmabuf->userfragsize;
+		cinfo.blocks = val/dmabuf->userfragsize;
 		cinfo.ptr = dmabuf->hwptr;
-		if (dmabuf->mapped) {
-			dmabuf->count &= (dmabuf->userfragsize-1);
+		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
+			dmabuf->count -= val;
+			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
 			__i810_update_lvi(state, 1);
 		}
 		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
 			cinfo.blocks, cinfo.ptr, dmabuf->count);
 #endif
@@ -1950,7 +2080,7 @@
 	case SNDCTL_DSP_SETTRIGGER:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
 		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
@@ -1960,7 +2090,7 @@
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if(val & PCM_ENABLE_OUTPUT) {
+		if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -1970,13 +2100,18 @@
 			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 				return ret;
 			if (dmabuf->mapped) {
-				dmabuf->count = dmabuf->dmasize;
-				i810_update_lvi(state,0);
-			}
-			if (!dmabuf->enable && dmabuf->count > dmabuf->userfragsize)
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_update_ptr(state);
+				dmabuf->count = 0;
+				dmabuf->swptr = dmabuf->hwptr;
+				dmabuf->count = i810_get_free_write_space(state);
+				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
+				__i810_update_lvi(state, 0);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			} else
 				start_dac(state);
 		}
-		if(val & PCM_ENABLE_INPUT) {
+		if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -1986,12 +2121,14 @@
 			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 				return ret;
 			if (dmabuf->mapped) {
+				spin_lock_irqsave(&state->card->lock, flags);
+				i810_update_ptr(state);
+				dmabuf->swptr = dmabuf->hwptr;
 				dmabuf->count = 0;
-				i810_update_lvi(state,1);
+				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
-			if (!dmabuf->enable && dmabuf->count <
-			    (dmabuf->dmasize - dmabuf->userfragsize))
-				start_adc(state);
+			i810_update_lvi(state, 1);
+			start_adc(state);
 		}
 		return 0;
 
@@ -2195,7 +2332,19 @@
 
 	/* find an avaiable virtual channel (instance of /dev/dsp) */
 	while (card != NULL) {
-		for (i = 0; i < NR_HW_CH; i++) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/20);
+		}
+		for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
 			if (card->states[i] == NULL) {
 				state = card->states[i] = (struct i810_state *)
 					kmalloc(sizeof(struct i810_state), GFP_KERNEL);
@@ -2229,8 +2378,8 @@
 			card->states[i] = NULL;;
 			return -EBUSY;
 		}
-		i810_set_adc_rate(state, 8000);
 		dmabuf->trigger |= PCM_ENABLE_INPUT;
+		i810_set_adc_rate(state, 8000);
 	}
 	if(file->f_mode & FMODE_WRITE) {
 		if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
@@ -2241,13 +2390,13 @@
 		/* Initialize to 8kHz?  What if we don't support 8kHz? */
 		/*  Let's change this to check for S/PDIF stuff */
 	
+		dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 		if ( spdif_locked ) {
 			i810_set_dac_rate(state, spdif_locked);
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
 		}
-		dmabuf->trigger |= PCM_ENABLE_OUTPUT;
 	}
 		
 	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
@@ -2274,11 +2423,10 @@
 	lock_kernel();
 
 	/* stop DMA state machine and free DMA buffers/channels */
-	if(dmabuf->enable & DAC_RUNNING ||
-	   (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
-		drain_dac(state,0);
+	if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
+		drain_dac(state, 0);
 	}
-	if(dmabuf->enable & ADC_RUNNING) {
+	if(dmabuf->trigger & PCM_ENABLE_INPUT) {
 		stop_adc(state);
 	}
 	spin_lock_irqsave(&card->lock, flags);
@@ -2344,13 +2492,26 @@
 	int minor = MINOR(inode->i_rdev);
 	struct i810_card *card = devs;
 
-	for (card = devs; card != NULL; card = card->next)
-		for (i = 0; i < NR_AC97; i++)
+	for (card = devs; card != NULL; card = card->next) {
+		/*
+		 * If we are initializing and then fail, card could go
+		 * away unuexpectedly while we are in the for() loop.
+		 * So, check for card on each iteration before we check
+		 * for card->initializing to avoid a possible oops.
+		 * This usually only matters for times when the driver is
+		 * autoloaded by kmod.
+		 */
+		for (i = 0; i < 50 && card && card->initializing; i++) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/20);
+		}
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
 				return 0;
 			}
+	}
 	return -ENODEV;
 }
 
@@ -2696,6 +2857,7 @@
 	}
 	memset(card, 0, sizeof(*card));
 
+	card->initializing = 1;
 	card->iobase = pci_resource_start (pci_dev, 1);
 	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
@@ -2752,7 +2914,8 @@
 	}
 	pci_set_drvdata(pci_dev, card);
 
-	if(clocking == 48000) {
+	if(clocking == 0) {
+		clocking = 48000;
 		i810_configure_clocking();
 	}
 
@@ -2771,7 +2934,7 @@
 		kfree(card);
 		return -ENODEV;
 	}
-
+ 	card->initializing = 0;
 	return 0;
 }
 
@@ -2789,6 +2952,7 @@
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
+			card->ac97_codec[i] = NULL;
 		}
 	unregister_sound_dsp(card->dev_audio);
 	kfree(card);
@@ -2957,14 +3121,11 @@
 	if(ftsodell != 0) {
 		printk("i810_audio: ftsodell is now a deprecated option.\n");
 	}
-	if(clocking == 48000) {
-		i810_configure_clocking();
-	}
 	if(spdif_locked > 0 ) {
 		if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
 			printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
 		} else {
-			printk("i810_audio: S/PDIF can only be locked to 32000, 441000, or 48000Hz.\n");
+			printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
 			spdif_locked = 0;
 		}
 	}
diff -urN linux-2.4.18-pre7/drivers/sound/mpu401.h linux/drivers/sound/mpu401.h
--- linux-2.4.18-pre7/drivers/sound/mpu401.h	Wed Sep 27 13:53:56 2000
+++ linux/drivers/sound/mpu401.h	Mon Feb  4 12:55:55 2002
@@ -1,9 +1,3 @@
-/*
- *	uart401.h 
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 /*	From uart401.c */
 int probe_uart401 (struct address_info *hw_config, struct module *owner);
diff -urN linux-2.4.18-pre7/drivers/sound/opl3.h linux/drivers/sound/opl3.h
--- linux-2.4.18-pre7/drivers/sound/opl3.h	Fri Aug 11 08:26:43 2000
+++ linux/drivers/sound/opl3.h	Mon Feb  4 12:55:55 2002
@@ -1,9 +1,3 @@
-/*
- *	opl3.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 int opl3_detect (int ioaddr, int *osp);
 int opl3_init(int ioaddr, int *osp, struct module *owner);
diff -urN linux-2.4.18-pre7/drivers/sound/pas2.h linux/drivers/sound/pas2.h
--- linux-2.4.18-pre7/drivers/sound/pas2.h	Tue Mar  7 13:40:24 2000
+++ linux/drivers/sound/pas2.h	Mon Feb  4 12:55:55 2002
@@ -1,9 +1,3 @@
-/*
- * pas2.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 /*	From pas_card.c	*/
 int pas_set_intr(int mask);
diff -urN linux-2.4.18-pre7/drivers/sound/pss.c linux/drivers/sound/pss.c
--- linux-2.4.18-pre7/drivers/sound/pss.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/pss.c	Mon Feb  4 12:55:55 2002
@@ -48,7 +48,7 @@
  *          Added module parameter pss_firmware to allow the user to tell 
  *          the driver where the fireware file is located.  The default 
  *          setting is the previous hardcoded setting "/etc/sound/pss_synth".
- * 00-03-03: Christoph Hellwig <chhellwig@gmx.net>
+ * 00-03-03: Christoph Hellwig <chhellwig@infradead.org>
  *	    Adapted to module_init/module_exit
  * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
  *	    Added __init to probe_pss(), attach_pss() and probe_pss_mpu()
diff -urN linux-2.4.18-pre7/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- linux-2.4.18-pre7/drivers/usb/ov511.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/usb/ov511.c	Mon Feb  4 12:55:55 2002
@@ -57,7 +57,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.48 for Linux 2.4"
+#define DRIVER_VERSION "v1.48a for Linux 2.4"
 #define EMAIL "mmcclell@bigfoot.com"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
@@ -492,6 +492,10 @@
 static struct proc_dir_entry *ov511_proc_entry = NULL;
 extern struct proc_dir_entry *video_proc_entry;
 
+static struct file_operations ov511_control_fops = {
+	ioctl:		ov511_control_ioctl,
+};
+
 #define YES_NO(x) ((x) ? "yes" : "no")
 
 /* /proc/video/ov511/<minor#>/info */
@@ -673,8 +677,8 @@
 		unlock_kernel();
 		return;
 	}
-	ov511->proc_control->proc_fops->ioctl = ov511_control_ioctl;
 	ov511->proc_control->data = ov511;
+	ov511->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
 }
 
@@ -6893,13 +6897,13 @@
 		}
 	}
 
-	usb_driver_release_interface(&ov511_driver,
-		&ov511->dev->actconfig->interface[ov511->iface]);
-	ov511->dev = NULL;
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
         destroy_proc_ov511_cam(ov511);
 #endif
+
+	usb_driver_release_interface(&ov511_driver,
+		&ov511->dev->actconfig->interface[ov511->iface]);
+	ov511->dev = NULL;
 
 	/* Free the memory */
 	if (ov511 && !ov511->user) {
diff -urN linux-2.4.18-pre7/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- linux-2.4.18-pre7/drivers/usb/pegasus.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/usb/pegasus.c	Mon Feb  4 12:55:55 2002
@@ -883,6 +883,7 @@
 	if ( reset_mac(pegasus) ) {
 		err("can't reset MAC");
 		unregister_netdev( pegasus->net );
+		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		return NULL;
@@ -919,6 +920,7 @@
 	pegasus->flags |= PEGASUS_UNPLUG;
 	unregister_netdev( pegasus->net );
 	usb_dec_dev_use( dev );
+	kfree( pegasus->net );
 	kfree( pegasus );
 	pegasus = NULL;
 }
diff -urN linux-2.4.18-pre7/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile
--- linux-2.4.18-pre7/drivers/usb/storage/Makefile	Sun Jul 29 21:11:50 2001
+++ linux/drivers/usb/storage/Makefile	Mon Feb  4 12:55:56 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the USB Mass Storage device drivers.
 #
-# 15 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# 15 Aug 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/drivers/usb/stv680.c linux/drivers/usb/stv680.c
--- linux-2.4.18-pre7/drivers/usb/stv680.c	Mon Feb  4 12:55:39 2002
+++ linux/drivers/usb/stv680.c	Mon Feb  4 12:55:56 2002
@@ -43,6 +43,13 @@
  * 			   Took out sharpen function, ran code through
  * 			   Lindent, and did other minor tweaks to get
  * 			   things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
 	swapRGB = 0;
-	PDEBUG (1, "STV(i): swapRGB is OFF");
-
+	if ((swapRGB_on == 0) && (swapRGB == 0))
+		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+	else if ((swapRGB_on == 1) && (swapRGB == 1))
+		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+	else if (swapRGB_on == 1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+	else if (swapRGB_on == -1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+	
 	if (stv_set_video_mode (stv680) < 0) {
 		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
 		return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@
 	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
 	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	if (swapRGB_on == 0)
+		out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+	else if (swapRGB_on == 1)
+		out += sprintf (out, "swapRGB         : (forced) on\n");
+	else if (swapRGB_on == -1)
+		out += sprintf (out, "swapRGB         : (forced) off\n");
+
 	out += sprintf (out, "Palette         : %i", stv680->palette);
 
 	out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
 	if (stv680->brightness != p->brightness) {
 		stv680->chgbright = 1;
 		stv680->brightness = p->brightness;
-	} else {
-		stv680->chgbright = 0;
-	}
+	} 
 
 	stv680->whiteness = p->whiteness;	/* greyscale */
 	stv680->colour = p->colour;
@@ -888,7 +908,7 @@
 {
 	int x, y, i;
 	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	int vw = stv680->cwidth, vh = stv680->cheight;
 	unsigned int p = 0;
 	int colour = 0, bayer = 0;
 	unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
 		return;
 	}
 
-	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
 		vw = 320;
 		vh = 240;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 352)) {
+	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
 		vw = 352;
 		vh = 288;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-		vstep = 2;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-		vstep = 2;
-	}
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
 
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
-
-			switch (vstep) {
-			case 1:
-				if (x & 1)
-					p = *(raw + y * w + (x >> 1));
-				else
-					p = *(raw + y * w + (x >> 1) + (w >> 1));
-				break;
-
-			case 2:
-				if (x & 1)
-					p = *(raw + ((y * w) << 1) + x);
-				else
-					p = *(raw + ((y * w) << 1) + x + (w >> 1));
-				break;
-			}
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
 
 			if (y & 1)
 				bayer = 2;
@@ -968,9 +965,10 @@
 				colour = 2;
 				break;
 			}
-			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			i = (y * vw + x) * 3;	
 			*(output + i + colour) = (unsigned char) p;
 		}		/* for x */
+
 	}			/* for y */
 
 	/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
 	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
 	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
 	   converted to unsigned char. Values are in stv680.h  */
+
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
 			i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
 		}		/* for x */
 	}			/* for y  - end demosaic  */
 
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+
+	/*  process all raw data, then trim to size if necessary */
+	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+		i = 0;
+		for (y = 0; y < vh; y++) {
+			if (!(y & 1)) {
+				for (x = 0; x < vw; x++) {
+					p = (y * vw + x) * 3;
+					if (!(x & 1)) {
+						*(output + i) = *(output + p);
+						*(output + i + 1) = *(output + p + 1);
+						*(output + i + 2) = *(output + p + 2);
+						i += 3;
+					}
+				}  /* for x */
+			}
+		}  /* for y */
+	}
+	/* reset to proper width */
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+	}
+
 	/* output is RGB; some programs want BGR  */
-	if (swapRGB == 1) {
+	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+	/* swapRGB_on=-1, never swap */
+	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
 		for (y = 0; y < vh; y++) {
 			for (x = 0; x < vw; x++) {
 				i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
 				return -EFAULT;
 			}
 			copy_from_user (&p, arg, sizeof (p));
-			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+			PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
 			if (stv680_set_pict (stv680, &p))
 				return -EINVAL;
@@ -1309,8 +1347,8 @@
 			if (vm.format != STV_VIDEO_PALETTE) {
 				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
 					vm.format, STV_VIDEO_PALETTE);
-				if (vm.format == 3) {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+				if ((vm.format == 3) && (swapRGB_on == 0))  {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
 					/* this may fix those apps (e.g., xawtv) that want BGR */
 					swapRGB = 1;
 				}
@@ -1320,8 +1358,10 @@
 				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
 				return -EINVAL;
 			}
-			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+			if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+			    || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+					stv680->frame[vm.frame].grabstate);
 				return -EBUSY;
 			}
 			/* Is this according to the v4l spec??? */
diff -urN linux-2.4.18-pre7/drivers/usb/stv680.h linux/drivers/usb/stv680.h
--- linux-2.4.18-pre7/drivers/usb/stv680.h	Mon Feb  4 12:55:39 2002
+++ linux/drivers/usb/stv680.h	Mon Feb  4 12:55:56 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID	0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@
 	int nullpackets;
 };
 
-unsigned char red[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
diff -urN linux-2.4.18-pre7/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- linux-2.4.18-pre7/drivers/usb/uhci.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/usb/uhci.c	Mon Feb  4 12:55:56 2002
@@ -520,7 +520,8 @@
 
 	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
 
-	uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
+		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
 
 	/* All qh's in the queue need to link to the next queue */
 	urbp->qh->link = eurbp->qh->link;
@@ -556,6 +557,7 @@
 
 	/* Fix up the toggle for the next URB's */
 	if (!urbp->queued)
+		/* We set the toggle when we unlink */
 		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 	else {
 		/* If we're in the middle of the queue, grab the toggle */
@@ -1683,8 +1685,8 @@
 
 		/* Control and Isochronous ignore the toggle, so this */
 		/* is safe for all types */
-		if (!(td->status & TD_CTRL_ACTIVE) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		if ((!(td->status & TD_CTRL_ACTIVE) &&
+		    (uhci_actual_length(td->status) < uhci_expected_length(td->info)) ||
 		    tmp == head)) {
 			usb_settoggle(urb->dev, uhci_endpoint(td->info),
 				uhci_packetout(td->info),
diff -urN linux-2.4.18-pre7/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- linux-2.4.18-pre7/drivers/usb/usb-uhci.c	Fri Dec 21 09:41:55 2001
+++ linux/drivers/usb/usb-uhci.c	Mon Feb  4 12:55:56 2002
@@ -16,7 +16,7 @@
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: usb-uhci.c,v 1.268 2001/08/29 14:08:43 acher Exp $
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
  */
 
 #include <linux/config.h>
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/pm.h>
+#include <linux/timer.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -52,7 +53,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.268 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -61,7 +62,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.268"
+#define DRIVER_VERSION "v1.275"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -71,6 +72,9 @@
 #define DEBUG_SYMBOLS
 #ifdef DEBUG_SYMBOLS
 	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
 #else
 	#define _static static
 #endif
@@ -1182,6 +1186,7 @@
 		// cleanup the rest
 		switch (usb_pipetype (urb->pipe)) {
 
+		case PIPE_INTERRUPT:
 		case PIPE_ISOCHRONOUS:
 			uhci_wait_ms(1);
 			uhci_clean_iso_step2(s, urb_priv);
@@ -1779,17 +1784,15 @@
 		type = usb_pipetype (urb->pipe);
 
 		hcpriv = (urb_priv_t*)urb->hcpriv;
-				
-		if ( urb->timeout && 
-			((hcpriv->started + urb->timeout) < jiffies)) {
+		
+		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
 			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
 			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
 		}
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-		     (hcpriv->use_loop) &&
-		     ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
 			disable_desc_loop(s, urb);
 #endif
 
@@ -2445,7 +2448,7 @@
 			break;
 		}
 
-		if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) {
+		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
 			// do not process one-shot TDs, no recycling
 			break;
 		}
@@ -2509,6 +2512,8 @@
 			}
 			else {
 				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				// correct toggle after unlink
+				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
 				clr_td_ioc(desc); // inactivate TD
 			}
 		}
@@ -2738,7 +2743,7 @@
 
 	if (status != 1) {
 		// Avoid too much error messages at a time
-		if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
 			warn("interrupt, status %x, frame# %i", status, 
 			     UHCI_GET_CURRENT_FRAME(s));
 			s->last_error_time = jiffies;
@@ -2786,7 +2791,7 @@
 				break;
 		}
 	}
-	if ((jiffies - s->timeout_check) > (HZ/30)) 
+	if (time_after(jiffies, s->timeout_check + (HZ/30)))
 		uhci_check_timeouts(s);
 
 	clean_descs(s, CLEAN_NOT_FORCED);
@@ -2815,7 +2820,7 @@
 _static void start_hc (uhci_t *s)
 {
 	unsigned int io_addr = s->io_addr;
-	int timeout = 1000;
+	int timeout = 10;
 
 	/*
 	 * Reset the HC - this will force us to get a
@@ -2830,6 +2835,7 @@
 			err("USBCMD_HCRESET timed out!");
 			break;
 		}
+		udelay(1);
 	}
 
 	/* Turn on all interrupts */
@@ -2845,7 +2851,8 @@
 	s->running = 1;
 }
 
-_static void __devexit
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
 uhci_pci_remove (struct pci_dev *dev)
 {
 	uhci_t *s = pci_get_drvdata(dev);
@@ -3070,7 +3077,7 @@
 	id_table:	&uhci_pci_ids [0],
 
 	probe:		uhci_pci_probe,
-	remove:		__devexit_p(uhci_pci_remove),
+	remove:		uhci_pci_remove,
 
 #ifdef	CONFIG_PM
 	suspend:	uhci_pci_suspend,
@@ -3130,4 +3137,3 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
-
diff -urN linux-2.4.18-pre7/fs/Makefile linux/fs/Makefile
--- linux-2.4.18-pre7/fs/Makefile	Mon Nov 12 09:34:16 2001
+++ linux/fs/Makefile	Mon Feb  4 12:55:57 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux filesystems.
 #
-# 14 Sep 2000, Christoph Hellwig <hch@caldera.de>
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 # 
 
diff -urN linux-2.4.18-pre7/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.18-pre7/fs/binfmt_elf.c	Mon Feb  4 12:55:39 2002
+++ linux/fs/binfmt_elf.c	Mon Feb  4 12:55:57 2002
@@ -138,6 +138,22 @@
 	} else
 		u_platform = p;
 
+#if defined(__i386__) && defined(CONFIG_SMP)
+	/*
+	 * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
+	 * by the processes running on the same package. One thing we can do
+	 * is to shuffle the initial stack for them.
+	 *
+	 * The conditionals here are unneeded, but kept in to make the
+	 * code behaviour the same as pre change unless we have hyperthreaded
+	 * processors. This keeps Mr Marcelo Person happier but should be
+	 * removed for 2.5
+	 */
+	 
+	if(smp_num_siblings > 1)
+		u_platform = u_platform - ((current->pid % 64) << 7);
+#endif	
+
 	/*
 	 * Force 16 byte _final_ alignment here for generality.
 	 */
@@ -505,32 +521,10 @@
 #if 0
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
-#ifdef __sparc__
-			if (ibcs2_interpreter) {
-				unsigned long old_pers = current->personality;
-				struct exec_domain *old_domain = current->exec_domain;
-				struct exec_domain *new_domain;
-				struct fs_struct *old_fs = current->fs, *new_fs;
-				get_exec_domain(old_domain);
-				atomic_inc(&old_fs->count);
-
-				set_personality(PER_SVR4);
-				interpreter = open_exec(elf_interpreter);
-
-				task_lock(current);
-				new_domain = current->exec_domain;
-				new_fs = current->fs;
-				current->personality = old_pers;
-				current->exec_domain = old_domain;
-				current->fs = old_fs;
-				task_unlock(current);
-				put_exec_domain(new_domain);
-				put_fs_struct(new_fs);
-			} else
-#endif
-			{
-				interpreter = open_exec(elf_interpreter);
-			}
+
+			SET_PERSONALITY(elf_ex, ibcs2_interpreter);
+
+			interpreter = open_exec(elf_interpreter);
 			retval = PTR_ERR(interpreter);
 			if (IS_ERR(interpreter))
 				goto out_free_interp;
@@ -603,10 +597,6 @@
 	current->mm->mmap = NULL;
 	current->flags &= ~PF_FORKNOEXEC;
 	elf_entry = (unsigned long) elf_ex.e_entry;
-
-	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
-	   may depend on the personality.  */
-	SET_PERSONALITY(elf_ex, ibcs2_interpreter);
 
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
diff -urN linux-2.4.18-pre7/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c
--- linux-2.4.18-pre7/fs/coda/coda_linux.c	Wed Apr 25 16:18:54 2001
+++ linux/fs/coda/coda_linux.c	Mon Feb  4 12:55:57 2002
@@ -172,6 +172,8 @@
 	        inode->i_mtime = attr->va_mtime.tv_sec;
         if (attr->va_ctime.tv_sec != -1)
 	        inode->i_ctime = attr->va_ctime.tv_sec;
+	if (!inode->i_ctime)
+		inode->i_ctime = inode->i_mtime;
 }
 
 
diff -urN linux-2.4.18-pre7/fs/coda/dir.c linux/fs/coda/dir.c
--- linux-2.4.18-pre7/fs/coda/dir.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/coda/dir.c	Mon Feb  4 12:55:57 2002
@@ -197,7 +197,7 @@
 	/* optimistically we can also act as if our nose bleeds. The
          * granularity of the mtime is coarse anyways so we might actually be
          * right most of the time. Note: we only do this for directories. */
-	dir->i_mtime = CURRENT_TIME;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 #endif
 	if (link)
 		dir->i_nlink += link;
@@ -209,7 +209,7 @@
         int error=0;
 	const char *name=de->d_name.name;
 	int length=de->d_name.len;
-	struct inode *result = NULL;
+	struct inode *inode = NULL;
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
@@ -230,16 +230,15 @@
 		return error;
 	}
 
-	error = coda_cnode_make(&result, &newfid, dir->i_sb);
-	if ( error ) {
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		d_drop(de);
-		result = NULL;
-		return error;
+		return PTR_ERR(inode);
 	}
 
 	/* invalidate the directory cnode's attributes */
 	coda_dir_changed(dir, 0);
-	d_instantiate(de, result);
+	d_instantiate(de, inode);
         return 0;
 }
 
@@ -519,6 +518,7 @@
 		result = vfs_readdir(file, filldir, dirent);
         }
 
+	UPDATE_ATIME(inode);
 	return result;
 }
 
@@ -657,7 +657,7 @@
 		goto bad;
 
 	cii = ITOC(de->d_inode);
-	if (cii->c_flags & (C_PURGE | C_FLUSH))
+	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
 		goto out;
 
 	shrink_dcache_parent(de);
diff -urN linux-2.4.18-pre7/fs/coda/file.c linux/fs/coda/file.c
--- linux-2.4.18-pre7/fs/coda/file.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/coda/file.c	Mon Feb  4 12:55:57 2002
@@ -36,6 +36,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 	struct file *cfile;
+	ssize_t ret;
 
 	cfile = cii->c_container;
 	if (!cfile) BUG();
@@ -43,7 +44,12 @@
 	if (!cfile->f_op || !cfile->f_op->read)
 		return -EINVAL;
 
-	return cfile->f_op->read(cfile, buf, count, ppos);
+	down(&inode->i_sem);
+	ret = cfile->f_op->read(cfile, buf, count, ppos);
+	UPDATE_ATIME(inode);
+	up(&inode->i_sem);
+
+	return ret;
 }
 
 static ssize_t
@@ -70,6 +76,7 @@
 
 	cfile->f_flags = flags;
 	inode->i_size = cinode->i_size;
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	up(&inode->i_sem);
 
 	return ret;
@@ -81,6 +88,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 	struct file *cfile;
+	int ret;
 
 	cfile = cii->c_container;
 
@@ -89,7 +97,12 @@
 	if (!cfile->f_op || !cfile->f_op->mmap)
 		return -ENODEV;
 
-	return cfile->f_op->mmap(cfile, vma);
+	down(&inode->i_sem);
+	ret = cfile->f_op->mmap(cfile, vma);
+	UPDATE_ATIME(inode);
+	up(&inode->i_sem);
+
+	return ret;
 }
 
 int coda_open(struct inode *i, struct file *f)
diff -urN linux-2.4.18-pre7/fs/coda/inode.c linux/fs/coda/inode.c
--- linux-2.4.18-pre7/fs/coda/inode.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/coda/inode.c	Mon Feb  4 12:55:57 2002
@@ -240,9 +240,11 @@
         struct coda_vattr vattr;
         int error;
 	
-        memset(&vattr, 0, sizeof(vattr)); 
+	inode->i_ctime = CURRENT_TIME;
 
+        memset(&vattr, 0, sizeof(vattr)); 
         coda_iattr_to_vattr(iattr, &vattr);
+
         vattr.va_type = C_VNON; /* cannot set type */
 	CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
 
diff -urN linux-2.4.18-pre7/fs/coda/psdev.c linux/fs/coda/psdev.c
--- linux-2.4.18-pre7/fs/coda/psdev.c	Fri Dec 21 09:41:55 2001
+++ linux/fs/coda/psdev.c	Mon Feb  4 12:55:57 2002
@@ -411,7 +411,7 @@
 static int __init init_coda(void)
 {
 	int status;
-	printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.15, coda@cs.cmu.edu\n");
+	printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.18, coda@cs.cmu.edu\n");
 
 	status = init_coda_psdev();
 	if ( status ) {
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs.h linux/fs/freevxfs/vxfs.h
--- linux-2.4.18-pre7/fs/freevxfs/vxfs.h	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs.h	Mon Feb  4 12:55:57 2002
@@ -30,7 +30,7 @@
 #ifndef _VXFS_SUPER_H_
 #define _VXFS_SUPER_H_
 
-#ident "$Id: vxfs.h 1.11 2001/05/21 15:40:28 hch Exp hch $"
+#ident "$Id: vxfs.h 1.12 2001/12/28 19:48:03 hch Exp $"
 
 /*
  * Veritas filesystem driver - superblock structure.
@@ -39,6 +39,7 @@
  * superblocks of the Veritas Filesystem.
  */
 #include <linux/types.h>
+#include "vxfs_kcompat.h"
 
 
 /*
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_bmap.c linux/fs/freevxfs/vxfs_bmap.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_bmap.c	Mon Feb  4 12:55:39 2002
+++ linux/fs/freevxfs/vxfs_bmap.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_bmap.c,v 1.23 2001/07/05 19:48:03 hch Exp hch $"
+#ident "$Id: vxfs_bmap.c,v 1.25 2002/01/02 23:36:55 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - filesystem to disk block mapping.
@@ -64,48 +64,46 @@
  *   The physical block number on success, else Zero.
  */
 static daddr_t
-vxfs_bmap_ext4(struct inode *ip, long iblock)
+vxfs_bmap_ext4(struct inode *ip, long bn)
 {
-	struct vxfs_inode_info		*vip = VXFS_INO(ip);
-	struct super_block		*sbp = ip->i_sb;
-	kdev_t				dev = ip->i_dev;
-	u_long				bsize = sbp->s_blocksize;
-	long				size = 0;
-	int				i;
+	struct super_block *sb = ip->i_sb;
+	struct vxfs_inode_info *vip = VXFS_INO(ip);
+	unsigned long bsize = sb->s_blocksize;
+	u32 indsize = vip->vii_ext4.ve4_indsize;
+	int i;
 
-	for (i = 0; i < VXFS_NDADDR; i++) {
-		struct direct		*dp = vip->vii_ext4.ve4_direct + i;
-
-#ifdef DIAGNOSTIC
-		printk(KERN_DEBUG "iblock: %ld, %d (size: %lu)\n", iblock, i, size);
-		printk(KERN_DEBUG "dp->extent: %d, dp->size: %d\n", dp->extent, dp->size);
-#endif
+	if (indsize > sb->s_blocksize)
+		goto fail_size;
 
-		if (iblock >= size && iblock < (size + dp->size))
-			return ((iblock - size) + dp->extent);
-		size += dp->size;
+	for (i = 0; i < VXFS_NDADDR; i++) {
+		struct direct *d = vip->vii_ext4.ve4_direct + i;
+		if (bn >= 0 && bn < d->size)
+			return (bn + d->extent);
+		bn -= d->size;
 	}
 
-	iblock -= size;
+	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
+		struct buffer_head *buf;
+		daddr_t	bno;
+		u32 *indir;
+
+		buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
+		if (!buf || !buffer_mapped(buf))
+			goto fail_buf;
 
-	if (!(iblock / (vip->vii_ext4.ve4_indsize * vip->vii_ext4.ve4_indsize * bsize >> 2))) {
-		struct buffer_head	*bp;
-		daddr_t			pblock;
-
-		/*
-		 * XXX: is the second indir only used for
-		 *	double indirect extents?
-		 */
-		bp = bread(dev, vip->vii_ext4.ve4_indir[0],
-				bsize * ((vip->vii_ext4.ve4_indsize) / bsize) + 1);
-		pblock = *(bp->b_data + ((iblock / vip->vii_ext4.ve4_indsize) %
-					(vip->vii_ext4.ve4_indsize * bsize)));
+		indir = (u32 *)buf->b_data;
+		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
 
-		brelse(bp);
-		return (pblock + (iblock % vip->vii_ext4.ve4_indsize));
+		brelse(buf);
+		return bno;
 	} else
 		printk(KERN_WARNING "no matching indir?");
 
+	return 0;
+
+fail_size:
+	printk("vxfs: indirect extent to big!\n");
+fail_buf:
 	return 0;
 }
 
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_extern.h linux/fs/freevxfs/vxfs_extern.h
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_extern.h	Sun Sep  2 10:34:36 2001
+++ linux/fs/freevxfs/vxfs_extern.h	Mon Feb  4 12:55:57 2002
@@ -30,7 +30,7 @@
 #ifndef _VXFS_EXTERN_H_
 #define _VXFS_EXTERN_H_
 
-#ident "$Id: vxfs_extern.h,v 1.21 2001/08/07 16:13:30 hch Exp hch $"
+#ident "$Id: vxfs_extern.h,v 1.22 2001/12/28 20:50:47 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - external prototypes.
@@ -71,7 +71,7 @@
 extern int			vxfs_read_olt(struct super_block *, u_long);
 
 /* vxfs_subr.c */
-extern struct page *		vxfs_get_page(struct inode *, u_long);
+extern struct page *		vxfs_get_page(struct address_space *, u_long);
 extern __inline__ void		vxfs_put_page(struct page *);
 extern struct buffer_head *	vxfs_bread(struct inode *, int);
 
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_fshead.c linux/fs/freevxfs/vxfs_fshead.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_fshead.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/freevxfs/vxfs_fshead.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_fshead.c,v 1.19 2001/08/07 16:14:10 hch Exp hch $"
+#ident "$Id: vxfs_fshead.c,v 1.20 2002/01/02 22:02:12 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - fileset header routines.
@@ -81,9 +81,9 @@
 	if (buffer_mapped(bp)) {
 		struct vxfs_fsh		*fhp;
 
-		if (!(fhp = kmalloc(sizeof(struct vxfs_fsh), SLAB_KERNEL)))
+		if (!(fhp = kmalloc(sizeof(*fhp), SLAB_KERNEL)))
 			return NULL;
-		memcpy(fhp, bp->b_data, sizeof(struct vxfs_fsh));
+		memcpy(fhp, bp->b_data, sizeof(*fhp));
 
 		brelse(bp);
 		return (fhp);
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_inode.c linux/fs/freevxfs/vxfs_inode.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_inode.c	Mon Feb  4 12:55:39 2002
+++ linux/fs/freevxfs/vxfs_inode.c	Mon Feb  4 12:55:57 2002
@@ -27,12 +27,13 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_inode.c,v 1.37 2001/08/07 16:13:30 hch Exp hch $"
+#ident "$Id: vxfs_inode.c,v 1.42 2002/01/02 23:51:36 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - inode routines.
  */
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
@@ -47,6 +48,7 @@
 extern struct inode_operations vxfs_immed_symlink_iops;
 
 static struct file_operations vxfs_file_operations = {
+	.open =			generic_file_open,
 	.llseek =		generic_file_llseek,
 	.read =			generic_file_read,
 	.mmap =			generic_file_mmap,
@@ -113,7 +115,7 @@
 		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL)))
 			goto fail;
 		dip = (struct vxfs_dinode *)(bp->b_data + offset);
-		memcpy(vip, dip, sizeof(struct vxfs_inode_info));
+		memcpy(vip, dip, sizeof(*vip));
 #ifdef DIAGNOSTIC
 		vxfs_dumpi(vip, ino);
 #endif
@@ -145,7 +147,7 @@
 	u_long				offset;
 
 	offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE;
-	pp = vxfs_get_page(ilistp, ino * VXFS_ISIZE / PAGE_SIZE);
+	pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE);
 
 	if (!IS_ERR(pp)) {
 		struct vxfs_inode_info	*vip;
@@ -155,7 +157,7 @@
 		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL)))
 			goto fail;
 		dip = (struct vxfs_dinode *)(kaddr + offset);
-		memcpy(vip, dip, sizeof(struct vxfs_inode_info));
+		memcpy(vip, dip, sizeof(*vip));
 #ifdef DIAGNOSTIC
 		vxfs_dumpi(vip, ino);
 #endif
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_lookup.c linux/fs/freevxfs/vxfs_lookup.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_lookup.c	Wed Jun 27 17:10:55 2001
+++ linux/fs/freevxfs/vxfs_lookup.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_lookup.c,v 1.19 2001/05/30 19:50:20 hch Exp hch $"
+#ident "$Id: vxfs_lookup.c,v 1.21 2002/01/02 22:00:13 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - lookup and other directory related code.
@@ -126,7 +126,7 @@
 		caddr_t			kaddr;
 		struct page		*pp;
 
-		pp = vxfs_get_page(ip, page);
+		pp = vxfs_get_page(ip->i_mapping, page);
 		if (IS_ERR(pp))
 			continue;
 		kaddr = (caddr_t)page_address(pp);
@@ -273,7 +273,7 @@
 		caddr_t			kaddr;
 		struct page		*pp;
 
-		pp = vxfs_get_page(ip, page);
+		pp = vxfs_get_page(ip->i_mapping, page);
 		if (IS_ERR(pp))
 			continue;
 		kaddr = (caddr_t)page_address(pp);
@@ -318,6 +318,5 @@
 done:
 	fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
 out:
-	fp->f_version = ip->i_version;
 	return 0;
 }
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_olt.c linux/fs/freevxfs/vxfs_olt.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_olt.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/freevxfs/vxfs_olt.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_olt.c,v 1.9 2001/08/07 16:14:45 hch Exp hch $"
+#ident "$Id: vxfs_olt.c,v 1.10 2002/01/02 23:03:58 hch Exp hch $"
 
 /* 
  * Veritas filesystem driver - object location table support.
@@ -85,14 +85,23 @@
 	char			*oaddr, *eaddr;
 
 
-	bp = bread(sbp->s_dev,
-			vxfs_oblock(sbp, infp->vsi_oltext, bsize), bsize);
+	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
 	if (!bp || !bp->b_data)
 		goto fail;
 
 	op = (struct vxfs_olt *)bp->b_data;
 	if (op->olt_magic != VXFS_OLT_MAGIC) {
 		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
+		goto fail;
+	}
+
+	/*
+	 * It is in theory possible that vsi_oltsize is > 1.
+	 * I've not seen any such filesystem yet and I'm lazy..  --hch
+	 */
+	if (infp->vsi_oltsize > 1) {
+		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
+		printk(KERN_NOTICE "vxfs: please notify hch@caldera.de\n");
 		goto fail;
 	}
 
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_subr.c linux/fs/freevxfs/vxfs_subr.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_subr.c	Mon Feb  4 12:55:39 2002
+++ linux/fs/freevxfs/vxfs_subr.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_subr.c,v 1.5 2001/04/26 22:49:51 hch Exp hch $"
+#ident "$Id: vxfs_subr.c,v 1.8 2001/12/28 20:50:47 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - shared subroutines.
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 
+#include "vxfs_kcompat.h"
 #include "vxfs_extern.h"
 
 
@@ -62,9 +63,8 @@
  *   The wanted page on success, else a NULL pointer.
  */
 struct page *
-vxfs_get_page(struct inode *ip, u_long n)
+vxfs_get_page(struct address_space *mapping, u_long n)
 {
-	struct address_space *		mapping = ip->i_mapping;
 	struct page *			pp;
 
 	pp = read_cache_page(mapping, n,
@@ -135,17 +135,14 @@
  *   Zero on success, else a negativ error code (-EIO).
  */
 static int
-vxfs_getblk(struct inode *ip, long iblock,
+vxfs_getblk(struct inode *ip, sector_t iblock,
 	    struct buffer_head *bp, int create)
 {
 	daddr_t			pblock;
 
 	pblock = vxfs_bmap1(ip, iblock);
 	if (pblock != 0) {
-		bp->b_dev = ip->i_dev;
-		bp->b_blocknr = pblock;
-		bp->b_state |= (1UL << BH_Mapped);
-
+		map_bh(bp, ip->i_sb, pblock);
 		return 0;
 	}
 
diff -urN linux-2.4.18-pre7/fs/freevxfs/vxfs_super.c linux/fs/freevxfs/vxfs_super.c
--- linux-2.4.18-pre7/fs/freevxfs/vxfs_super.c	Thu Oct 11 09:43:38 2001
+++ linux/fs/freevxfs/vxfs_super.c	Mon Feb  4 12:55:57 2002
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_super.c,v 1.26 2001/08/07 16:13:30 hch Exp hch $"
+#ident "$Id: vxfs_super.c,v 1.29 2002/01/02 22:02:12 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - superblock related routines.
@@ -62,19 +62,6 @@
 	.statfs =		vxfs_statfs,
 };
 
-static __inline__ u_long
-vxfs_validate_bsize(kdev_t dev)
-{
-	u_long			bsize;
-	
-	bsize = get_hardsect_size(dev);
-	if (bsize < BLOCK_SIZE)
-		bsize = BLOCK_SIZE;
-
-	set_blocksize(dev, bsize);
-	return (bsize);
-}
-
 /**
  * vxfs_put_super - free superblock resources
  * @sbp:	VFS superblock.
@@ -153,21 +140,24 @@
 {
 	struct vxfs_sb_info	*infp;
 	struct vxfs_sb		*rsbp;
-	struct buffer_head	*bp;
+	struct buffer_head	*bp = NULL;
 	u_long			bsize;
-	kdev_t			dev = sbp->s_dev;
 
-	infp = kmalloc(sizeof(struct vxfs_sb_info), GFP_KERNEL);
+	infp = kmalloc(sizeof(*infp), GFP_KERNEL);
 	if (!infp) {
 		printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
 		return NULL;
 	}
-	memset(infp, 0, sizeof(struct vxfs_sb_info));
+	memset(infp, 0, sizeof(*infp));
 
-	bsize = vxfs_validate_bsize(dev);
+	bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
+	if (!bsize) {
+		printk(KERN_WARNING "vxfs: unable to set blocksize\n");
+		goto out;
+	}
 
-	bp = bread(dev, 1, bsize);
-	if (!bp) {
+	bp = sb_bread(sbp, 1);
+	if (!bp || !buffer_mapped(bp)) {
 		if (!silent) {
 			printk(KERN_WARNING
 				"vxfs: unable to read disk superblock\n");
@@ -194,31 +184,15 @@
 #endif
 
 	sbp->s_magic = rsbp->vs_magic;
-	sbp->s_blocksize = rsbp->vs_bsize;
 	sbp->u.generic_sbp = (void *)infp;
 
 	infp->vsi_raw = rsbp;
 	infp->vsi_bp = bp;
 	infp->vsi_oltext = rsbp->vs_oltext[0];
 	infp->vsi_oltsize = rsbp->vs_oltsize;
-	
 
-	switch (rsbp->vs_bsize) {
-	case 1024:
-		sbp->s_blocksize_bits = 10;
-		break;
-	case 2048:
-		sbp->s_blocksize_bits = 11;
-		break;
-	case 4096:
-		sbp->s_blocksize_bits = 12;
-		break;
-	default:
-		if (!silent) {
-			printk(KERN_WARNING
-				"vxfs: unsupported blocksise: %d\n",
-				rsbp->vs_bsize);
-		}
+	if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
+		printk(KERN_WARNING "vxfs: unable to set final block size\n");
 		goto out;
 	}
 
diff -urN linux-2.4.18-pre7/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- linux-2.4.18-pre7/fs/nfsd/nfssvc.c	Wed Oct 17 14:16:34 2001
+++ linux/fs/nfsd/nfssvc.c	Mon Feb  4 12:55:57 2002
@@ -99,7 +99,7 @@
 		if (error < 0)
 			goto failure;
 #endif
-		get_fast_time(&nfssvc_boot);		/* record boot time */
+		do_gettimeofday(&nfssvc_boot);		/* record boot time */
 	} else
 		nfsd_serv->sv_nrthreads++;
 	nrservs -= (nfsd_serv->sv_nrthreads-1);
diff -urN linux-2.4.18-pre7/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c
--- linux-2.4.18-pre7/fs/reiserfs/namei.c	Mon Feb  4 12:55:39 2002
+++ linux/fs/reiserfs/namei.c	Mon Feb  4 12:55:57 2002
@@ -1043,7 +1043,7 @@
     INITIALIZE_PATH (old_entry_path);
     INITIALIZE_PATH (new_entry_path);
     INITIALIZE_PATH (dot_dot_entry_path);
-    struct item_head new_entry_ih, old_entry_ih ;
+    struct item_head new_entry_ih, old_entry_ih, dot_dot_ih ;
     struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
     struct inode * old_inode, * new_inode;
     int windex ;
@@ -1132,6 +1132,8 @@
 
 	copy_item_head(&old_entry_ih, get_ih(&old_entry_path)) ;
 
+	reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1) ;
+
 	// look for new name by reiserfs_find_entry
 	new_de.de_gen_number_bit_string = 0;
 	retval = reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
@@ -1146,6 +1148,7 @@
 	if (S_ISDIR(old_inode->i_mode)) {
 	    if (search_by_entry_key (new_dir->i_sb, &dot_dot_de.de_entry_key, &dot_dot_entry_path, &dot_dot_de) != NAME_FOUND)
 		BUG ();
+	    copy_item_head(&dot_dot_ih, get_ih(&dot_dot_entry_path)) ;
 	    // node containing ".." gets into transaction
 	    reiserfs_prepare_for_journal(old_inode->i_sb, dot_dot_de.de_bh, 1) ;
 	}
@@ -1162,23 +1165,33 @@
 	** of the above checks could have scheduled.  We have to be
 	** sure our items haven't been shifted by another process.
 	*/
-	if (!entry_points_to_object(new_dentry->d_name.name, 
+	if (item_moved(&new_entry_ih, &new_entry_path) ||
+	    !entry_points_to_object(new_dentry->d_name.name, 
 	                            new_dentry->d_name.len,
 				    &new_de, new_inode) ||
-	    item_moved(&new_entry_ih, &new_entry_path) ||
 	    item_moved(&old_entry_ih, &old_entry_path) || 
 	    !entry_points_to_object (old_dentry->d_name.name, 
 	                             old_dentry->d_name.len,
 				     &old_de, old_inode)) {
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
+	    reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
 	    if (S_ISDIR(old_inode->i_mode))
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
 	    continue;
 	}
+	if (S_ISDIR(old_inode->i_mode)) {
+	    if ( item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
+		 !entry_points_to_object ( "..", 2, &dot_dot_de, old_dir) ) {
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
+		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
+		continue;
+	    }
+	}
+
 
 	RFALSE( S_ISDIR(old_inode->i_mode) && 
-		(!entry_points_to_object ("..", 2, &dot_dot_de, old_dir) || 
-		 !reiserfs_buffer_prepared(dot_dot_de.de_bh)), "" );
+		!reiserfs_buffer_prepared(dot_dot_de.de_bh), "" );
 
 	break;
     }
@@ -1191,6 +1204,7 @@
     journal_mark_dirty (&th, old_dir->i_sb, new_de.de_bh);
 
     mark_de_hidden (old_de.de_deh + old_de.de_entry_num);
+    journal_mark_dirty (&th, old_dir->i_sb, old_de.de_bh);
     old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
     new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 
diff -urN linux-2.4.18-pre7/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog
--- linux-2.4.18-pre7/fs/sysv/ChangeLog	Mon Feb  4 12:55:40 2002
+++ linux/fs/sysv/ChangeLog	Mon Feb  4 12:55:57 2002
@@ -4,7 +4,7 @@
 	  waitfor_one_page() for IS_SYNC directories, so that we
 	  actually do sync the directory.
 
-Sat Dec 15 2001  Christoph Hellwig  <hch@caldera.de>
+Sat Dec 15 2001  Christoph Hellwig  <hch@infradead.org>
 
 	* inode.c (sysv_read_inode): Mark inode as bad in case of failure.
 	* super.c (complete_read_super): Check for bad root inode.
@@ -13,13 +13,13 @@
 
 	* file.c (sysv_sync_file): Call fsync_inode_data_buffers.
 
-Fri Oct 26 2001  Christoph Hellwig  <hch@caldera.de>
+Fri Oct 26 2001  Christoph Hellwig  <hch@infradead.org>
 
 	* dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h:
 	Implement per-Inode lookup offset cache.
 	Modelled after Ted's ext2 patch.
 
-Fri Oct 26 2001  Christoph Hellwig  <hch@caldera.de>
+Fri Oct 26 2001  Christoph Hellwig  <hch@infradead.org>
 
 	* inode.c, super.c, include/linux/sysv_fs.h,
 	  include/linux/sysv_fs_sb.h:
diff -urN linux-2.4.18-pre7/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- linux-2.4.18-pre7/fs/sysv/symlink.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/sysv/symlink.c	Mon Feb  4 12:55:57 2002
@@ -2,7 +2,7 @@
  *  linux/fs/sysv/symlink.c
  *
  *  Handling of System V filesystem fast symlinks extensions.
- *  Aug 2001, Christoph Hellwig (hch@caldera.de)
+ *  Aug 2001, Christoph Hellwig (hch@infradead.org)
  */
 
 #include <linux/fs.h>
diff -urN linux-2.4.18-pre7/fs/ufs/swab.h linux/fs/ufs/swab.h
--- linux-2.4.18-pre7/fs/ufs/swab.h	Mon Nov 19 14:55:46 2001
+++ linux/fs/ufs/swab.h	Mon Feb  4 12:55:57 2002
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1997, 1998 Francois-Rene Rideau <fare@tunes.org>
  * Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
- * Copyright (C) 2001 Christoph Hellwig <hch@caldera.de>
+ * Copyright (C) 2001 Christoph Hellwig <hch@infradead.org>
  */
 
 #ifndef _UFS_SWAB_H
diff -urN linux-2.4.18-pre7/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- linux-2.4.18-pre7/include/asm-i386/pci.h	Mon Feb  4 12:55:40 2002
+++ linux/include/asm-i386/pci.h	Mon Feb  4 12:55:57 2002
@@ -118,7 +118,7 @@
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 #define pci_unmap_addr(PTR, ADDR_NAME)		(0)
-#define pci_unmap_addr_SET(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
 #define pci_unmap_len(PTR, LEN_NAME)		(0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
diff -urN linux-2.4.18-pre7/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- linux-2.4.18-pre7/include/asm-i386/unistd.h	Wed Oct 17 10:03:03 2001
+++ linux/include/asm-i386/unistd.h	Mon Feb  4 12:55:57 2002
@@ -230,6 +230,18 @@
 #define __NR_security		223	/* syscall for security modules */
 #define __NR_gettid		224
 #define __NR_readahead		225
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -urN linux-2.4.18-pre7/include/asm-ppc/keylargo.h linux/include/asm-ppc/keylargo.h
--- linux-2.4.18-pre7/include/asm-ppc/keylargo.h	Mon Feb  4 12:55:40 2002
+++ linux/include/asm-ppc/keylargo.h	Mon Feb  4 12:55:57 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.keylargo.h 1.15 12/01/01 20:09:11 benh
+ * BK Id: SCCS/s.keylargo.h 1.17 01/20/02 23:53:12 benh
  */
 /*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
@@ -27,6 +27,7 @@
 #define KEYLARGO_GPIO_EXTINT_CNT	18
 #define KEYLARGO_GPIO_0			0x6A
 #define KEYLARGO_GPIO_CNT		17
+#define KEYLARGO_GPIO_EXTINT_DUAL_EDGE	0x80
 #define KEYLARGO_GPIO_OUTPUT_ENABLE	0x04
 #define KEYLARGO_GPIO_OUTOUT_DATA	0x01
 #define KEYLARGO_GPIO_INPUT_DATA	0x02
@@ -87,8 +88,8 @@
 #define KL_MBCR_MB1_DEV_RESET		0x02000000
 #define KL_MBCR_MB1_ENABLE		0x01000000
 
-#define KL0_SCC_B_INTF_ENABLE		0x00000001	/* ??? */
-#define KL0_SCC_A_INTF_ENABLE		0x00000002	/* ??? */
+#define KL0_SCC_B_INTF_ENABLE		0x00000001
+#define KL0_SCC_A_INTF_ENABLE		0x00000002
 #define KL0_SCC_SLOWPCLK		0x00000004
 #define KL0_SCC_RESET			0x00000008
 #define KL0_SCCA_ENABLE			0x00000010
@@ -137,8 +138,9 @@
 #define KL2_IOBUS_ENABLE		0x00000002
 #define KL2_SLEEP_STATE_BIT		0x00000100
 #define KL2_MPIC_ENABLE			0x00020000
-#define KL2_MODEM_POWER_N		0x02000000
-#define KL2_AIRPORT_RESET_N		0x08000000	/* Or power ? */
+#define KL2_ALT_DATA_OUT		0x02000000
+#define KL2_MEM_IS_BIG			0x04000000
+#define KL2_CARDSEL_16			0x08000000
 
 #define KL3_SHUTDOWN_PLL_TOTAL		0x00000001
 #define KL3_SHUTDOWN_PLLKW6		0x00000002
@@ -158,11 +160,11 @@
 #define KL3_STOPPING33_ENABLED		0x00080000
 
 /* Port 0,1 : bus 0, port 2,3 : bus 1 */
-#define KL4_SET_PORT_ENABLE(p)		(0x00000008 << ((p)<<3))
-#define KL4_SET_PORT_RESUME(p)		(0x00000004 << ((p)<<3))
-#define KL4_SET_PORT_CONNECT(p)		(0x00000002 << ((p)<<3))
-#define KL4_SET_PORT_DISCONNECT(p)	(0x00000001 << ((p)<<3))
-#define KL4_GET_PORT_RESUME(p)		(0x00000040 << ((p)<<3))
-#define KL4_GET_PORT_CONNECT(p)		(0x00000020 << ((p)<<3))
-#define KL4_GET_PORT_DISCONNECT(p)	(0x00000010 << ((p)<<3))
+#define KL4_PORT_WAKEUP_ENABLE(p)	(0x00000008 << ((p)<<3))
+#define KL4_PORT_RESUME_WAKE_EN(p)	(0x00000004 << ((p)<<3))
+#define KL4_PORT_CONNECT_WAKE_EN(p)	(0x00000002 << ((p)<<3))
+#define KL4_PORT_DISCONNECT_WAKE_EN(p)	(0x00000001 << ((p)<<3))
+#define KL4_PORT_RESUME_STAT(p)		(0x00000040 << ((p)<<3))
+#define KL4_PORT_CONNECT_STAT(p)	(0x00000020 << ((p)<<3))
+#define KL4_PORT_DISCONNECT_STAT(p)	(0x00000010 << ((p)<<3))
 
diff -urN linux-2.4.18-pre7/include/asm-ppc/pmac_feature.h linux/include/asm-ppc/pmac_feature.h
--- linux-2.4.18-pre7/include/asm-ppc/pmac_feature.h	Mon Feb  4 12:55:40 2002
+++ linux/include/asm-ppc/pmac_feature.h	Mon Feb  4 12:55:57 2002
@@ -97,6 +97,7 @@
  */
 
 #define PMAC_MB_CAN_SLEEP		0x00000001
+#define PMAC_MB_HAS_FW_POWER		0x00000002
 
 /*
  * Feature calls supported on pmac
diff -urN linux-2.4.18-pre7/include/linux/capi.h linux/include/linux/capi.h
--- linux-2.4.18-pre7/include/linux/capi.h	Sun Sep 30 12:26:42 2001
+++ linux/include/linux/capi.h	Mon Feb  4 12:55:57 2002
@@ -1,4 +1,4 @@
-/* $Id: capi.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $
+/* $Id: capi.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
  * 
  * CAPI 2.0 Interface for Linux
  * 
diff -urN linux-2.4.18-pre7/include/linux/coda_fs_i.h linux/include/linux/coda_fs_i.h
--- linux-2.4.18-pre7/include/linux/coda_fs_i.h	Thu Nov 22 11:46:19 2001
+++ linux/include/linux/coda_fs_i.h	Mon Feb  4 12:55:57 2002
@@ -33,6 +33,7 @@
 #define C_PURGE       0x8
 
 int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
+struct inode *coda_iget(struct super_block *sb, struct ViceFid *fid, struct coda_vattr *attr);
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
 void coda_replace_fid(struct inode *, ViceFid *, ViceFid *);
diff -urN linux-2.4.18-pre7/include/linux/generic_serial.h linux/include/linux/generic_serial.h
--- linux-2.4.18-pre7/include/linux/generic_serial.h	Fri Sep  7 09:28:38 2001
+++ linux/include/linux/generic_serial.h	Mon Feb  4 12:55:57 2002
@@ -12,9 +12,6 @@
 #ifndef GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 
-
-
-
 struct real_driver {
   void                    (*disable_tx_interrupts) (void *);
   void                    (*enable_tx_interrupts) (void *);
@@ -98,7 +95,7 @@
                      struct termios * old_termios);
 int  gs_init_port(struct gs_port *port);
 int  gs_setserial(struct gs_port *port, struct serial_struct *sp);
-void gs_getserial(struct gs_port *port, struct serial_struct *sp);
+int  gs_getserial(struct gs_port *port, struct serial_struct *sp);
 void gs_got_break(struct gs_port *port);
 
 extern int gs_debug;
diff -urN linux-2.4.18-pre7/include/linux/kernelcapi.h linux/include/linux/kernelcapi.h
--- linux-2.4.18-pre7/include/linux/kernelcapi.h	Thu Feb  8 10:40:25 2001
+++ linux/include/linux/kernelcapi.h	Mon Feb  4 12:55:57 2002
@@ -1,10 +1,12 @@
-/*
- * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $
+/* $Id: kernelcapi.h,v 1.1.4.2 2002/01/28 18:25:10 kai Exp $
  * 
  * Kernel CAPI 2.0 Interface for Linux
  * 
  * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #ifndef __KERNELCAPI_H__
diff -urN linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_ULOG.h linux/include/linux/netfilter_ipv4/ipt_ULOG.h
--- linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_ULOG.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ULOG.h	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,46 @@
+/* Header file for IP tables userspace logging, Version 1.8
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * Distributed under the terms of GNU GPL */
+
+#ifndef _IPT_ULOG_H
+#define _IPT_ULOG_H
+
+#ifndef NETLINK_NFLOG
+#define NETLINK_NFLOG 	5
+#endif
+
+#define ULOG_MAC_LEN	80
+#define ULOG_PREFIX_LEN	32
+
+#define ULOG_MAX_QLEN	50
+/* Why 50? Well... there is a limit imposed by the slab cache 131000
+ * bytes. So the multipart netlink-message has to be < 131000 bytes.
+ * Assuming a standard ethernet-mtu of 1500, we could define this up
+ * to 80... but even 50 seems to be big enough. */
+
+/* private data structure for each rule with a ULOG target */
+struct ipt_ulog_info {
+	unsigned int nl_group;
+	size_t copy_range;
+	size_t qthreshold;
+	char prefix[ULOG_PREFIX_LEN];
+};
+
+/* Format of the ULOG packets passed through netlink */
+typedef struct ulog_packet_msg {
+	unsigned long mark;
+	long timestamp_sec;
+	long timestamp_usec;
+	unsigned int hook;
+	char indev_name[IFNAMSIZ];
+	char outdev_name[IFNAMSIZ];
+	size_t data_len;
+	char prefix[ULOG_PREFIX_LEN];
+	unsigned char mac_len;
+	unsigned char mac[ULOG_MAC_LEN];
+	unsigned char payload[0];
+} ulog_packet_msg_t;
+
+#endif /*_IPT_ULOG_H*/
diff -urN linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_ah.h linux/include/linux/netfilter_ipv4/ipt_ah.h
--- linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_ah.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ah.h	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_AH_H
+#define _IPT_AH_H
+
+struct ipt_ah
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_ah. */
+#define IPT_AH_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_AH_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_AH_H*/
diff -urN linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_esp.h linux/include/linux/netfilter_ipv4/ipt_esp.h
--- linux-2.4.18-pre7/include/linux/netfilter_ipv4/ipt_esp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_esp.h	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_ESP_H
+#define _IPT_ESP_H
+
+struct ipt_esp
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_esp. */
+#define IPT_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_ESP_H*/
diff -urN linux-2.4.18-pre7/include/linux/netfilter_ipv4.h linux/include/linux/netfilter_ipv4.h
--- linux-2.4.18-pre7/include/linux/netfilter_ipv4.h	Thu Nov 22 11:48:57 2001
+++ linux/include/linux/netfilter_ipv4.h	Mon Feb  4 12:55:57 2002
@@ -73,4 +73,81 @@
 /* 2.4 firewalling went 64 through 67. */
 #define SO_ORIGINAL_DST 80
 
+
+/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue 
+ *
+ * Ideally this would be ins some netfilter_utility module, but creating this
+ * module for just one function doesn't make sense. -HW */
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/route.h>
+#include <linux/ip.h>
+
+static inline int route_me_harder(struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct rtable *rt;
+	struct rt_key key = { dst:iph->daddr,
+			      src:iph->saddr,
+			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
+			      tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+			      fwmark:(*pskb)->nfmark
+#endif
+			    };
+	struct net_device *dev_src = NULL;
+	int err;
+
+	/* accomodate ip_route_output_slow(), which expects the key src to be
+	   0 or a local address; however some non-standard hacks like
+	   ipt_REJECT.c:send_reset() can cause packets with foreign
+           saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
+	if(key.src && !(dev_src = ip_dev_find(key.src)))
+		key.src = 0;
+
+	if ((err=ip_route_output_key(&rt, &key)) != 0) {
+		printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
+			NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
+			(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
+			RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+			(*pskb)->nfmark,
+#else
+			0UL,
+#endif
+			err);
+		goto out;
+	}
+
+	/* Drop old route. */
+	dst_release((*pskb)->dst);
+
+	(*pskb)->dst = &rt->u.dst;
+
+	/* Change in oif may mean change in hh_len. */
+	if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+		struct sk_buff *nskb;
+
+		nskb = skb_realloc_headroom(*pskb,
+					    (*pskb)->dst->dev->hard_header_len);
+		if (!nskb) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if ((*pskb)->sk)
+			skb_set_owner_w(nskb, (*pskb)->sk);
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
+out:
+	if (dev_src)
+		dev_put(dev_src);
+
+	return err;
+}
+
 #endif /*__LINUX_IP_NETFILTER_H*/
diff -urN linux-2.4.18-pre7/include/linux/time.h linux/include/linux/time.h
--- linux-2.4.18-pre7/include/linux/time.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/time.h	Mon Feb  4 12:55:57 2002
@@ -100,8 +100,6 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
-extern void get_fast_time(struct timeval *tv);
-extern void (*do_get_fast_time)(struct timeval *);
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
diff -urN linux-2.4.18-pre7/include/net/route.h linux/include/net/route.h
--- linux-2.4.18-pre7/include/net/route.h	Thu Nov 22 11:47:15 2001
+++ linux/include/net/route.h	Mon Feb  4 12:55:57 2002
@@ -30,6 +30,7 @@
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
+#include <linux/ip.h>
 #include <linux/cache.h>
 
 #ifndef __KERNEL__
diff -urN linux-2.4.18-pre7/include/scsi/scsi.h linux/include/scsi/scsi.h
--- linux-2.4.18-pre7/include/scsi/scsi.h	Fri Apr 27 13:59:19 2001
+++ linux/include/scsi/scsi.h	Mon Feb  4 12:55:57 2002
@@ -130,6 +130,7 @@
 
 #define TYPE_DISK           0x00
 #define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
 #define TYPE_PROCESSOR      0x03    /* HP scanners use this */
 #define TYPE_WORM           0x04    /* Treated as ROM by our system */
 #define TYPE_ROM            0x05
diff -urN linux-2.4.18-pre7/kernel/exec_domain.c linux/kernel/exec_domain.c
--- linux-2.4.18-pre7/kernel/exec_domain.c	Fri Dec 21 09:42:04 2001
+++ linux/kernel/exec_domain.c	Mon Feb  4 12:55:57 2002
@@ -4,7 +4,7 @@
  * We group personalities into execution domains which have their
  * own handlers for kernel entry points, signal mapping, etc...
  *
- * 2001-05-06	Complete rewrite,  Christoph Hellwig (hch@caldera.de)
+ * 2001-05-06	Complete rewrite,  Christoph Hellwig (hch@infradead.org)
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.18-pre7/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.18-pre7/kernel/ksyms.c	Mon Feb  4 12:55:40 2002
+++ linux/kernel/ksyms.c	Mon Feb  4 12:55:57 2002
@@ -200,6 +200,7 @@
 EXPORT_SYMBOL(__wait_on_buffer);
 EXPORT_SYMBOL(___wait_on_page);
 EXPORT_SYMBOL(generic_direct_IO);
+EXPORT_SYMBOL(discard_bh_page);
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_prepare_write);
@@ -529,9 +530,6 @@
 
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
-
-/* time */
-EXPORT_SYMBOL(get_fast_time);
 
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
diff -urN linux-2.4.18-pre7/kernel/ptrace.c linux/kernel/ptrace.c
--- linux-2.4.18-pre7/kernel/ptrace.c	Fri Dec 21 09:42:04 2001
+++ linux/kernel/ptrace.c	Mon Feb  4 12:55:57 2002
@@ -173,6 +173,7 @@
 		put_page(page);
 		len -= bytes;
 		buf += bytes;
+		addr += bytes;
 	}
 	up_read(&mm->mmap_sem);
 	mmput(mm);
diff -urN linux-2.4.18-pre7/kernel/time.c linux/kernel/time.c
--- linux-2.4.18-pre7/kernel/time.c	Fri Dec 21 09:42:04 2001
+++ linux/kernel/time.c	Mon Feb  4 12:55:57 2002
@@ -36,24 +36,6 @@
  */
 struct timezone sys_tz;
 
-static void do_normal_gettime(struct timeval * tm)
-{
-        *tm=xtime;
-}
-
-void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
-
-/*
- * Generic way to access 'xtime' (the current time of day).
- * This can be changed if the platform provides a more accurate (and fast!) 
- * version.
- */
-
-void get_fast_time(struct timeval * t)
-{
-	do_get_fast_time(t);
-}
-
 /* The xtime_lock is not only serializing the xtime read/writes but it's also
    serializing all accesses to the global NTP variables now. */
 extern rwlock_t xtime_lock;
diff -urN linux-2.4.18-pre7/net/Makefile linux/net/Makefile
--- linux-2.4.18-pre7/net/Makefile	Fri Dec 21 09:42:05 2001
+++ linux/net/Makefile	Mon Feb  4 12:55:57 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the linux networking.
 #
-# 2 Sep 2000, Christoph Hellwig <hch@caldera.de>
+# 2 Sep 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
 #
 
diff -urN linux-2.4.18-pre7/net/core/dev.c linux/net/core/dev.c
--- linux-2.4.18-pre7/net/core/dev.c	Mon Feb  4 12:55:40 2002
+++ linux/net/core/dev.c	Mon Feb  4 12:55:57 2002
@@ -875,7 +875,7 @@
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct packet_type *ptype;
-	get_fast_time(&skb->stamp);
+	do_gettimeofday(&skb->stamp);
 
 	br_read_lock(BR_NETPROTO_LOCK);
 	for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 
@@ -1218,7 +1218,7 @@
 	unsigned long flags;
 
 	if (skb->stamp.tv_sec == 0)
-		get_fast_time(&skb->stamp);
+		do_gettimeofday(&skb->stamp);
 
 	/* The code is rearranged so that the path is the most
 	   short when CPU is congested, but is still operating.
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ip_nat_standalone.c	Mon Feb  4 12:55:40 2002
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Mon Feb  4 12:55:57 2002
@@ -166,46 +166,6 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-static int route_me_harder(struct sk_buff **pskb)
-{
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:(*pskb)->nfmark
-#endif
-			    };
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release((*pskb)->dst);
-
-	(*pskb)->dst = &rt->u.dst;
-
-	/* Change in oif may mean change in hh_len. */
-	if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
-		struct sk_buff *nskb;
-
-		nskb = skb_realloc_headroom(*pskb,
-					    (*pskb)->dst->dev
-					    ->hard_header_len);
-		if (!nskb)
-			return -ENOMEM;
-		if ((*pskb)->sk)
-			skb_set_owner_w(nskb, (*pskb)->sk);
-		kfree_skb(*pskb);
-		*pskb = nskb;
-	}
-	return 0;
-}
-
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
 		struct sk_buff **pskb,
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ip_queue.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_queue.c	Mon Feb  4 12:55:57 2002
@@ -216,32 +216,6 @@
 	kfree(q);
 }
 
-/* With a chainsaw... */
-static int route_me_harder(struct sk_buff *skb)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct rtable *rt;
-
-	struct rt_key key = {
-				dst:iph->daddr, src:iph->saddr,
-				oif:skb->sk ? skb->sk->bound_dev_if : 0,
-				tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-				fwmark:skb->nfmark
-#endif
-			};
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-	skb->dst = &rt->u.dst;
-	return 0;
-}
-
 static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
 {
 	int diff;
@@ -287,7 +261,7 @@
 		if (!(iph->tos == e->rt_info.tos
 		      && iph->daddr == e->rt_info.daddr
 		      && iph->saddr == e->rt_info.saddr))
-			return route_me_harder(e->skb);
+			return route_me_harder(&e->skb);
 	}
 	return 0;
 }
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ipfwadm_core.c	Mon Feb  4 12:55:40 2002
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Mon Feb  4 12:55:57 2002
@@ -20,7 +20,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.9.2.1 2002/01/23 13:18:19 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.9.2.2 2002/01/24 15:50:42 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -688,7 +688,7 @@
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
 		kfree(ftmp);
-		MOD_DEC_USE_COUNT();
+		MOD_DEC_USE_COUNT;
 	}
 	restore_flags(flags);
 }
@@ -732,7 +732,7 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	restore_flags(flags);
-	MOD_INC_USE_COUNT();
+	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -783,7 +783,7 @@
 	else
         	*chainptr=ftmp;
 	restore_flags(flags);
-	MOD_INC_USE_COUNT();
+	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -858,7 +858,7 @@
 	}
 	restore_flags(flags);
 	if (was_found) {
-		MOD_DEC_USE_COUNT();
+		MOD_DEC_USE_COUNT;
 		return 0;
 	} else
 		return(EINVAL);
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ipt_ULOG.c linux/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ipt_ULOG.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ULOG.c	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,349 @@
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
+ * 						<zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue. 
+ *            nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ * 	      module loadtime -HW
+ *
+ * Released under the terms of the GPL
+ *
+ * This module accepts two parameters: 
+ * 
+ * nlbufsiz:
+ *   The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ *   Specify, after how many clock ticks (intel: 100 per second) the queue
+ * should be flushed even if it is not full yet.
+ *
+ * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+
+#define ULOG_NL_EVENT		111		/* Harald's favorite number */
+#define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
+
+#if 0
+#define DEBUGP(format, args...)	printk(__FILE__ ":" __FUNCTION__ ":" \
+				       format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
+
+
+static unsigned int nlbufsiz = 4096;
+MODULE_PARM(nlbufsiz, "i");
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
+
+static unsigned int flushtimeout = 10 * HZ;
+MODULE_PARM(flushtimeout, "i");
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
+
+/* global data structures */
+
+typedef struct {
+	unsigned int qlen;		/* number of nlmsgs' in the skb */
+	struct nlmsghdr *lastnlh;	/* netlink header of last msg in skb */
+	struct sk_buff *skb;		/* the pre-allocated skb */
+	struct timer_list timer;	/* the timer function */
+} ulog_buff_t;
+
+static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];	/* array of buffers */
+
+static struct sock *nflognl;	/* our socket */
+static size_t qlen;		/* current length of multipart-nlmsg */
+DECLARE_LOCK(ulog_lock);	/* spinlock */
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+	ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+	if (timer_pending(&ub->timer)) {
+		DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+		del_timer(&ub->timer);
+	}
+
+	/* last nlmsg needs NLMSG_DONE */
+	if (ub->qlen > 1)
+		ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+	NETLINK_CB(ub->skb).dst_groups = nlgroup;
+	DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
+		ub->qlen, nlgroup);
+	netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+
+	ub->qlen = 0;
+	ub->skb = NULL;
+	ub->lastnlh = NULL;
+
+}
+
+
+/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
+static void ulog_timer(unsigned long data)
+{
+	DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+
+	/* lock to protect against somebody modifying our structure
+	 * from ipt_ulog_target at the same time */
+	LOCK_BH(&ulog_lock);
+	ulog_send(data);
+	UNLOCK_BH(&ulog_lock);
+}
+
+static void nflog_rcv(struct sock *sk, int len)
+{
+	printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
+}
+
+struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+	struct sk_buff *skb;
+
+	/* alloc skb which should be big enough for a whole
+	 * multipart message. WARNING: has to be <= 131000
+	 * due to slab allocator restrictions */
+
+	skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+	if (!skb) {
+		PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
+			nlbufsiz);
+
+		/* try to allocate only as much as we need for 
+		 * current packet */
+
+		skb = alloc_skb(size, GFP_ATOMIC);
+		if (!skb)
+			PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+	}
+
+	return skb;
+}
+
+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+				    unsigned int hooknum,
+				    const struct net_device *in,
+				    const struct net_device *out,
+				    const void *targinfo, void *userinfo)
+{
+	ulog_buff_t *ub;
+	ulog_packet_msg_t *pm;
+	size_t size, copy_len;
+	struct nlmsghdr *nlh;
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	/* calculate the size of the skb needed */
+	if ((loginfo->copy_range == 0) ||
+	    (loginfo->copy_range > (*pskb)->len)) {
+		copy_len = (*pskb)->len;
+	} else {
+		copy_len = loginfo->copy_range;
+	}
+
+	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+
+	ub = &ulog_buffers[loginfo->nl_group];
+	
+	LOCK_BH(&ulog_lock);
+
+	if (!ub->skb) {
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	} else if (ub->qlen >= loginfo->qthreshold ||
+		   size > skb_tailroom(ub->skb)) {
+		/* either the queue len is too high or we don't have 
+		 * enough room in nlskb left. send it to userspace. */
+
+		ulog_send(loginfo->nl_group);
+
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	}
+
+	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
+		loginfo->qthreshold);
+
+	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
+	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
+			size - sizeof(*nlh));
+	ub->qlen++;
+
+	pm = NLMSG_DATA(nlh);
+
+	/* copy hook, prefix, timestamp, payload, etc. */
+	pm->data_len = copy_len;
+	pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+	pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+	pm->mark = (*pskb)->nfmark;
+	pm->hook = hooknum;
+	if (loginfo->prefix[0] != '\0')
+		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+	else
+		*(pm->prefix) = '\0';
+
+	if (in && in->hard_header_len > 0
+	    && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
+	    && in->hard_header_len <= ULOG_MAC_LEN) {
+		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
+		pm->mac_len = in->hard_header_len;
+	}
+
+	if (in)
+		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+	else
+		pm->indev_name[0] = '\0';
+
+	if (out)
+		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
+	else
+		pm->outdev_name[0] = '\0';
+
+	if (copy_len)
+		memcpy(pm->payload, (*pskb)->data, copy_len);
+	
+	/* check if we are building multi-part messages */
+	if (ub->qlen > 1) {
+		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+	}
+
+	/* if threshold is reached, send message to userspace */
+	if (qlen >= loginfo->qthreshold) {
+		if (loginfo->qthreshold > 1)
+			nlh->nlmsg_type = NLMSG_DONE;
+	}
+
+	ub->lastnlh = nlh;
+
+	/* if timer isn't already running, start it */
+	if (!timer_pending(&ub->timer)) {
+		ub->timer.expires = jiffies + flushtimeout;
+		add_timer(&ub->timer);
+	}
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+
+
+nlmsg_failure:
+	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+
+alloc_failure:
+	PRINTR("ipt_ULOG: Error building netlink message\n");
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+}
+
+static int ipt_ulog_checkentry(const char *tablename,
+			       const struct ipt_entry *e,
+			       void *targinfo,
+			       unsigned int targinfosize,
+			       unsigned int hookmask)
+{
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
+		DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
+		return 0;
+	}
+
+	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+		DEBUGP("ipt_ULOG: prefix term %i\n",
+		       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+		return 0;
+	}
+
+	if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+		DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
+			loginfo->qthreshold);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ulog_reg =
+    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
+THIS_MODULE
+};
+
+static int __init init(void)
+{
+	int i;
+
+	DEBUGP("ipt_ULOG: init module\n");
+
+	if (nlbufsiz >= 128*1024) {
+		printk("Netlink buffer has to be <= 128kB\n");
+		return -EINVAL;
+	}
+
+	/* initialize ulog_buffers */
+	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+		memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
+		init_timer(&ulog_buffers[i].timer);
+		ulog_buffers[i].timer.function = ulog_timer;
+		ulog_buffers[i].timer.data = i;
+	}
+
+	nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+	if (!nflognl)
+		return -ENOMEM;
+
+	if (ipt_register_target(&ipt_ulog_reg) != 0) {
+		sock_release(nflognl->socket);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	DEBUGP("ipt_ULOG: cleanup_module\n");
+
+	ipt_unregister_target(&ipt_ulog_reg);
+	sock_release(nflognl->socket);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ipt_ah.c linux/net/ipv4/netfilter/ipt_ah.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ipt_ah.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ah.c	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_ah.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct ahhdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ahhdr *ah = hdr;
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct ahhdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil AH tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(ahinfo->spis[0], ahinfo->spis[1],
+			      ntohl(ah->spi),
+			      !!(ahinfo->invflags & IPT_AH_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	/* Must specify proto == AH, and no unknown invflags */
+	if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_AH);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
+		duprintf("ipt_ah: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
+		return 0;
+	}
+	if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
+		duprintf("ipt_ah: unknown flags %X\n",
+			 ahinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+int __init init(void)
+{
+	return ipt_register_match(&ah_match);
+}
+
+void __exit cleanup(void)
+{
+	ipt_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/ipt_esp.c linux/net/ipv4/netfilter/ipt_esp.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/ipt_esp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_esp.c	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_esp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct esphdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct esphdr *esp = hdr;
+	const struct ipt_esp *espinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct esphdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil ESP tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(espinfo->spis[0], espinfo->spis[1],
+			      ntohl(esp->spi),
+			      !!(espinfo->invflags & IPT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_esp *espinfo = matchinfo;
+
+	/* Must specify proto == ESP, and no unknown invflags */
+	if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_ESP);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
+		duprintf("ipt_esp: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
+		return 0;
+	}
+	if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
+		duprintf("ipt_esp: unknown flags %X\n",
+			 espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+	ipt_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.4.18-pre7/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c
--- linux-2.4.18-pre7/net/ipv4/netfilter/iptable_mangle.c	Mon Feb  4 12:55:40 2002
+++ linux/net/ipv4/netfilter/iptable_mangle.c	Mon Feb  4 12:55:57 2002
@@ -129,34 +129,6 @@
 	return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 }
 
-/* FIXME: change in oif may mean change in hh_len.  Check and realloc
-   --RR */
-static int
-route_me_harder(struct sk_buff *skb)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:skb->sk ? skb->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:skb->nfmark
-#endif
-			    };
-
-	if (ip_route_output_key(&rt, &key) != 0) {
-		printk("route_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-
-	skb->dst = &rt->u.dst;
-	return 0;
-}
-
 static unsigned int
 ipt_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
@@ -190,7 +162,7 @@
 		|| (*pskb)->nh.iph->daddr != daddr
 		|| (*pskb)->nfmark != nfmark
 		|| (*pskb)->nh.iph->tos != tos))
-		return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+		return route_me_harder(pskb) == 0 ? ret : NF_DROP;
 
 	return ret;
 }
diff -urN linux-2.4.18-pre7/net/ipv6/netfilter/ip6_queue.c linux/net/ipv6/netfilter/ip6_queue.c
--- linux-2.4.18-pre7/net/ipv6/netfilter/ip6_queue.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv6/netfilter/ip6_queue.c	Mon Feb  4 12:55:57 2002
@@ -0,0 +1,721 @@
+/*
+ * This is a module which is used for queueing IPv6 packets and
+ * communicating with userspace via netlink.
+ *
+ * (C) 2001 Fernando Anton, this code is GPL.
+ *     IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ *     Universidad Carlos III de Madrid - Leganes (Madrid) - Spain
+ *     Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain
+ *     email: fanton@it.uc3m.es
+ *
+ * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
+ *             to adapt it to IPv6
+ *             HEAVILY based in ipqueue.c by James Morris. It's just
+ *             a little modified version of it, so he's nearly the
+ *             real coder of this.
+ *             Few changes needed, mainly the hard_routing code and
+ *             the netlink socket protocol (we're NETLINK_IP6_FW).
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+/* We're still usign the following structs. No need to change them: */
+/*   ipq_packet_msg                                                 */
+/*   ipq_mode_msg                                                   */
+/*   ipq_verdict_msg                                                */
+/*   ipq_peer_msg                                                   */
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define IPQ_QMAX_DEFAULT 1024
+#define IPQ_PROC_FS_NAME "ip6_queue"
+#define NET_IPQ_QMAX 2088
+#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
+
+typedef struct ip6q_rt_info {
+	struct in6_addr daddr;
+	struct in6_addr saddr;
+} ip6q_rt_info_t;
+
+typedef struct ip6q_queue_element {
+	struct list_head list;		/* Links element into queue */
+	int verdict;			/* Current verdict */
+	struct nf_info *info;		/* Extra info from netfilter */
+	struct sk_buff *skb;		/* Packet inside */
+	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
+} ip6q_queue_element_t;
+
+typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
+
+typedef struct ip6q_peer {
+	pid_t pid;			/* PID of userland peer */
+	unsigned char died;		/* We think the peer died */
+	unsigned char copy_mode;	/* Copy packet as well as metadata? */
+	size_t copy_range;		/* Range past metadata to copy */
+	ip6q_send_cb_t send;		/* Callback for sending data to peer */
+} ip6q_peer_t;
+
+typedef struct ip6q_queue {
+ 	int len;			/* Current queue len */
+ 	int *maxlen;			/* Maximum queue len, via sysctl */
+ 	unsigned char flushing;		/* If queue is being flushed */
+ 	unsigned char terminate;	/* If the queue is being terminated */
+ 	struct list_head list;		/* Head of packet queue */
+ 	spinlock_t lock;		/* Queue spinlock */
+ 	ip6q_peer_t peer;		/* Userland peer */
+} ip6q_queue_t;
+
+/****************************************************************************
+ *
+ * Packet queue
+ *
+ ****************************************************************************/
+/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
+static ip6q_queue_element_t *
+ip6q_dequeue(ip6q_queue_t *q,
+            int (*cmp)(ip6q_queue_element_t *, unsigned long),
+            unsigned long data)
+{
+	struct list_head *i;
+
+	spin_lock_bh(&q->lock);
+	for (i = q->list.prev; i != &q->list; i = i->prev) {
+		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
+		
+		if (!cmp || cmp(e, data)) {
+			list_del(&e->list);
+			q->len--;
+			spin_unlock_bh(&q->lock);
+			return e;
+		}
+	}
+	spin_unlock_bh(&q->lock);
+	return NULL;
+}
+
+/* Flush all packets */
+static void ip6q_flush(ip6q_queue_t *q)
+{
+	ip6q_queue_element_t *e;
+	
+	spin_lock_bh(&q->lock);
+	q->flushing = 1;
+	spin_unlock_bh(&q->lock);
+	while ((e = ip6q_dequeue(q, NULL, 0))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+	spin_lock_bh(&q->lock);
+	q->flushing = 0;
+	spin_unlock_bh(&q->lock);
+}
+
+static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
+                                     ip6q_send_cb_t send_cb,
+                                     int *errp, int *sysctl_qmax)
+{
+	int status;
+	ip6q_queue_t *q;
+
+	*errp = 0;
+	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
+	if (q == NULL) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	q->peer.pid = 0;
+	q->peer.died = 0;
+	q->peer.copy_mode = IPQ_COPY_NONE;
+	q->peer.copy_range = 0;
+	q->peer.send = send_cb;
+	q->len = 0;
+	q->maxlen = sysctl_qmax;
+	q->flushing = 0;
+	q->terminate = 0;
+	INIT_LIST_HEAD(&q->list);
+	spin_lock_init(&q->lock);
+	status = nf_register_queue_handler(PF_INET6, outfn, q);
+	if (status < 0) {
+		*errp = -EBUSY;
+		kfree(q);
+		return NULL;
+	}
+	return q;
+}
+
+static int ip6q_enqueue(ip6q_queue_t *q,
+                       struct sk_buff *skb, struct nf_info *info)
+{
+	ip6q_queue_element_t *e;
+	int status;
+	
+	e = kmalloc(sizeof(*e), GFP_ATOMIC);
+	if (e == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+		return -ENOMEM;
+	}
+
+	e->verdict = NF_DROP;
+	e->info = info;
+	e->skb = skb;
+
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = skb->nh.ipv6h;
+
+		e->rt_info.daddr = iph->daddr;
+		e->rt_info.saddr = iph->saddr;
+	}
+
+	spin_lock_bh(&q->lock);
+	if (q->len >= *q->maxlen) {
+		spin_unlock_bh(&q->lock);
+		if (net_ratelimit()) 
+			printk(KERN_WARNING "ip6_queue: full at %d entries, "
+			       "dropping packet(s).\n", q->len);
+		goto free_drop;
+	}
+	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
+		spin_unlock_bh(&q->lock);
+		goto free_drop;
+	}
+	status = q->peer.send(e);
+	if (status > 0) {
+		list_add(&e->list, &q->list);
+		q->len++;
+		spin_unlock_bh(&q->lock);
+		return status;
+	}
+	spin_unlock_bh(&q->lock);
+	if (status == -ECONNREFUSED) {
+		printk(KERN_INFO "ip6_queue: peer %d died, "
+		       "resetting state and flushing queue\n", q->peer.pid);
+			q->peer.died = 1;
+			q->peer.pid = 0;
+			q->peer.copy_mode = IPQ_COPY_NONE;
+			q->peer.copy_range = 0;
+			ip6q_flush(q);
+	}
+free_drop:
+	kfree(e);
+	return -EBUSY;
+}
+
+static void ip6q_destroy_queue(ip6q_queue_t *q)
+{
+	nf_unregister_queue_handler(PF_INET6);
+	spin_lock_bh(&q->lock);
+	q->terminate = 1;
+	spin_unlock_bh(&q->lock);
+	ip6q_flush(q);
+	kfree(q);
+}
+
+/*
+ * Taken from net/ipv6/ip6_output.c
+ *
+ * We should use the one there, but is defined static
+ * so we put this just here and let the things as
+ * they are now.
+ *
+ * If that one is modified, this one should be modified too.
+ */
+static int route6_me_harder(struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct dst_entry *dst;
+	struct flowi fl;
+
+	fl.proto = iph->nexthdr;
+	fl.fl6_dst = &iph->daddr;
+	fl.fl6_src = &iph->saddr;
+	fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
+	fl.fl6_flowlabel = 0;
+	fl.uli_u.ports.dport = 0;
+	fl.uli_u.ports.sport = 0;
+
+	dst = ip6_route_output(skb->sk, &fl);
+
+	if (dst->error) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+		return -EINVAL;
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+
+	skb->dst = dst;
+	return 0;
+}
+static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+{
+	int diff;
+	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+
+	if (v->data_len < sizeof(*user_iph))
+		return 0;
+	diff = v->data_len - e->skb->len;
+	if (diff < 0)
+		skb_trim(e->skb, v->data_len);
+	else if (diff > 0) {
+		if (v->data_len > 0xFFFF)
+			return -EINVAL;
+		if (diff > skb_tailroom(e->skb)) {
+			struct sk_buff *newskb;
+			
+			newskb = skb_copy_expand(e->skb,
+			                         skb_headroom(e->skb),
+			                         diff,
+			                         GFP_ATOMIC);
+			if (newskb == NULL) {
+				printk(KERN_WARNING "ip6_queue: OOM "
+				      "in mangle, dropping packet\n");
+				return -ENOMEM;
+			}
+			if (e->skb->sk)
+				skb_set_owner_w(newskb, e->skb->sk);
+			kfree_skb(e->skb);
+			e->skb = newskb;
+		}
+		skb_put(e->skb, diff);
+	}
+	memcpy(e->skb->data, v->payload, v->data_len);
+	e->skb->nfcache |= NFC_ALTERED;
+
+	/*
+	 * Extra routing may needed on local out, as the QUEUE target never
+	 * returns control to the table.
+         * Not a nice way to cmp, but works
+	 */
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = e->skb->nh.ipv6h;
+		if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
+                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
+                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
+                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
+		      && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
+		      && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
+		      && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
+		      && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+			return route6_me_harder(e->skb);
+	}
+	return 0;
+}
+
+static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+{
+	return (id == (unsigned long )e);
+}
+
+static int ip6q_set_verdict(ip6q_queue_t *q,
+                           ipq_verdict_msg_t *v, unsigned int len)
+{
+	ip6q_queue_element_t *e;
+
+	if (v->value > NF_MAX_VERDICT)
+		return -EINVAL;
+	e = ip6q_dequeue(q, id_cmp, v->id);
+	if (e == NULL)
+		return -ENOENT;
+	else {
+		e->verdict = v->value;
+		if (v->data_len && v->data_len == len)
+			if (ip6q_mangle_ipv6(v, e) < 0)
+				e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+		return 0;
+	}
+}
+
+static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
+                            unsigned char type, unsigned int len)
+{
+
+	int status = 0;
+	int busy;
+		
+	spin_lock_bh(&q->lock);
+	busy = (q->terminate || q->flushing);
+	spin_unlock_bh(&q->lock);
+	if (busy)
+		return -EBUSY;
+	if (len < sizeof(ipq_peer_msg_t))
+		return -EINVAL;
+	switch (type) {
+		case IPQM_MODE:
+			switch (m->msg.mode.value) {
+				case IPQ_COPY_META:
+					q->peer.copy_mode = IPQ_COPY_META;
+					q->peer.copy_range = 0;
+					break;
+				case IPQ_COPY_PACKET:
+					q->peer.copy_mode = IPQ_COPY_PACKET;
+					q->peer.copy_range = m->msg.mode.range;
+					if (q->peer.copy_range > 0xFFFF)
+						q->peer.copy_range = 0xFFFF;
+					break;
+				default:
+					status = -EINVAL;
+			}
+			break;
+		case IPQM_VERDICT:
+			if (m->msg.verdict.value > NF_MAX_VERDICT)
+				status = -EINVAL;
+			else
+				status = ip6q_set_verdict(q,
+				                         &m->msg.verdict,
+				                         len - sizeof(*m));
+			break;
+		default:
+			 status = -EINVAL;
+	}
+	return status;
+}
+
+static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+{
+	if (e->info->indev)
+		if (e->info->indev->ifindex == ifindex)
+			return 1;
+	if (e->info->outdev)
+		if (e->info->outdev->ifindex == ifindex)
+			return 1;
+	return 0;
+}
+
+/* Drop any queued packets associated with device ifindex */
+static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+{
+	ip6q_queue_element_t *e;
+	
+	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+}
+
+/****************************************************************************
+ *
+ * Netfilter interface
+ *
+ ****************************************************************************/
+
+/*
+ * Packets arrive here from netfilter for queuing to userspace.
+ * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
+ */
+static int netfilter6_receive(struct sk_buff *skb,
+                             struct nf_info *info, void *data)
+{
+	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
+}
+
+/****************************************************************************
+ *
+ * Netlink interface.
+ *
+ ****************************************************************************/
+
+static struct sock *nfnl = NULL;
+/* This is not a static one, so we should not repeat its name */
+ip6q_queue_t *nlq6 = NULL;
+
+static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	ipq_packet_msg_t *pm;
+	struct nlmsghdr *nlh;
+
+	switch (nlq6->peer.copy_mode) {
+		size_t copy_range;
+
+		case IPQ_COPY_META:
+			size = NLMSG_SPACE(sizeof(*pm));
+			data_len = 0;
+			break;
+		case IPQ_COPY_PACKET:
+			copy_range = nlq6->peer.copy_range;
+			if (copy_range == 0 || copy_range > e->skb->len)
+				data_len = e->skb->len;
+			else
+				data_len = copy_range;
+			size = NLMSG_SPACE(sizeof(*pm) + data_len);
+			
+			break;
+		case IPQ_COPY_NONE:
+		default:
+			*errp = -EINVAL;
+			return NULL;
+	}
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pm = NLMSG_DATA(nlh);
+	memset(pm, 0, sizeof(*pm));
+	pm->packet_id = (unsigned long )e;
+	pm->data_len = data_len;
+	pm->timestamp_sec = e->skb->stamp.tv_sec;
+	pm->timestamp_usec = e->skb->stamp.tv_usec;
+	pm->mark = e->skb->nfmark;
+	pm->hook = e->info->hook;
+	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
+	else pm->indev_name[0] = '\0';
+	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
+	else pm->outdev_name[0] = '\0';
+	pm->hw_protocol = e->skb->protocol;
+	if (e->info->indev && e->skb->dev) {
+		pm->hw_type = e->skb->dev->type;
+		if (e->skb->dev->hard_header_parse)
+			pm->hw_addrlen =
+				e->skb->dev->hard_header_parse(e->skb,
+				                               pm->hw_addr);
+	}
+	if (data_len)
+		memcpy(pm->payload, e->skb->data, data_len);
+	nlh->nlmsg_len = skb->tail - old_tail;
+	NETLINK_CB(skb).dst_groups = 0;
+	return skb;
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = 0;
+	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
+	return NULL;
+}
+
+static int netlink_send_peer(ip6q_queue_element_t *e)
+{
+	int status = 0;
+	struct sk_buff *skb;
+
+	skb = netlink_build_message(e, &status);
+	if (skb == NULL)
+		return status;
+	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+
+static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+{
+	int status, type;
+	struct nlmsghdr *nlh;
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+	    || skb->len < nlh->nlmsg_len)
+	    	return;
+
+	if(nlh->nlmsg_pid <= 0
+	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
+	    || nlh->nlmsg_flags & NLM_F_MULTI)
+		RCV_SKB_FAIL(-EINVAL);
+	if (nlh->nlmsg_flags & MSG_TRUNC)
+		RCV_SKB_FAIL(-ECOMM);
+	type = nlh->nlmsg_type;
+	if (type < NLMSG_NOOP || type >= IPQM_MAX)
+		RCV_SKB_FAIL(-EINVAL);
+	if (type <= IPQM_BASE)
+		return;
+	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+		RCV_SKB_FAIL(-EPERM);
+	if (nlq6->peer.pid && !nlq6->peer.died
+	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
+	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
+	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
+		ip6q_flush(nlq6);
+	}	
+	nlq6->peer.pid = nlh->nlmsg_pid;
+	nlq6->peer.died = 0;
+	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
+	                          type, skb->len - NLMSG_LENGTH(0));
+	if (status < 0)
+		RCV_SKB_FAIL(status);
+	if (nlh->nlmsg_flags & NLM_F_ACK)
+		netlink_ack(skb, nlh, 0);
+        return;
+}
+
+/* Note: we are only dealing with single part messages at the moment. */
+static void netlink_receive_user_sk(struct sock *sk, int len)
+{
+	do {
+		struct sk_buff *skb;
+
+		if (rtnl_shlock_nowait())
+			return;
+		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+			netlink_receive_user_skb(skb);
+			kfree_skb(skb);
+		}
+		up(&rtnl_sem);
+	} while (nfnl && nfnl->receive_queue.qlen);
+}
+
+/****************************************************************************
+ *
+ * System events
+ *
+ ****************************************************************************/
+
+static int receive_event(struct notifier_block *this,
+                         unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	/* Drop any packets associated with the downed device */
+	if (event == NETDEV_DOWN)
+		ip6q_dev_drop(nlq6, dev->ifindex);
+	return NOTIFY_DONE;
+}
+
+struct notifier_block ip6q_dev_notifier = {
+	receive_event,
+	NULL,
+	0
+};
+
+/****************************************************************************
+ *
+ * Sysctl - queue tuning.
+ *
+ ****************************************************************************/
+
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+
+static struct ctl_table_header *ip6q_sysctl_header;
+
+static ctl_table ip6q_table[] = {
+	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
+	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+ 	{ 0 }
+};
+
+static ctl_table ip6q_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+static ctl_table ip6q_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+/****************************************************************************
+ *
+ * Procfs - debugging info.
+ *
+ ****************************************************************************/
+
+static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	int len;
+
+	spin_lock_bh(&nlq6->lock);
+	len = sprintf(buffer,
+	              "Peer pid            : %d\n"
+	              "Peer died           : %d\n"
+	              "Peer copy mode      : %d\n"
+	              "Peer copy range     : %Zu\n"
+	              "Queue length        : %d\n"
+	              "Queue max. length   : %d\n"
+	              "Queue flushing      : %d\n"
+	              "Queue terminate     : %d\n",
+	              nlq6->peer.pid,
+	              nlq6->peer.died,
+	              nlq6->peer.copy_mode,
+	              nlq6->peer.copy_range,
+	              nlq6->len,
+	              *nlq6->maxlen,
+	              nlq6->flushing,
+	              nlq6->terminate);
+	spin_unlock_bh(&nlq6->lock);
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	else if (len < 0)
+		len = 0;
+	return len;
+}
+
+/****************************************************************************
+ *
+ * Module stuff.
+ *
+ ****************************************************************************/
+
+static int __init init(void)
+{
+	int status = 0;
+	struct proc_dir_entry *proc;
+	
+        /* We must create the NETLINK_IP6_FW protocol service */
+	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
+	if (nfnl == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create kernel netlink socket\n");
+		return -ENOMEM;
+	}
+	nlq6 = ip6q_create_queue(netfilter6_receive,
+	                       netlink_send_peer, &status, &sysctl_maxlen);
+	if (nlq6 == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create queue\n");
+		sock_release(nfnl->socket);
+		return status;
+	}
+        /* The file will be /proc/net/ip6_queue */
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
+	if (proc) proc->owner = THIS_MODULE;
+	else {
+		ip6q_destroy_queue(nlq6);
+		sock_release(nfnl->socket);
+		return -ENOMEM;
+	}
+	register_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+}
+
+static void __exit fini(void)
+{
+	unregister_sysctl_table(ip6q_sysctl_header);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	unregister_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_destroy_queue(nlq6);
+	sock_release(nfnl->socket);
+}
+
+MODULE_DESCRIPTION("IPv6 packet queue handler");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.18-pre7/net/ipv6/proc.c linux/net/ipv6/proc.c
--- linux-2.4.18-pre7/net/ipv6/proc.c	Sun Jul  9 22:30:41 2000
+++ linux/net/ipv6/proc.c	Mon Feb  4 12:55:57 2002
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.15 2000/07/07 22:29:42 davem Exp $
+ * Version:	$Id: proc.c,v 1.15.2.1 2002/01/24 15:46:07 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -37,7 +37,7 @@
 	return res;
 }
 
-int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+int afinet6_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len = 0;
 	len += sprintf(buffer+len, "TCP6: inuse %d\n",
