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

diff -urN linux-2.4.19-pre2/CREDITS linux-2.4.19-pre3/CREDITS
--- linux-2.4.19-pre2/CREDITS	Mon Mar 11 14:13:07 2002
+++ linux-2.4.19-pre3/CREDITS	Mon Mar 11 14:13:24 2002
@@ -586,6 +586,13 @@
 S: University of Michigan
 S: Ann Arbor, MI
 
+N: Michael Cornwell
+E: cornwell@acm.org
+D: Original designer and co-author of ATA Taskfile
+D: Kernel module SMART utilities
+S: Santa Cruz, California
+S: USA
+
 N: Kees Cook
 E: cook@cpoint.net
 W: http://outflux.net/
@@ -1184,22 +1191,19 @@
 
 N: Andre Hedrick
 E: andre@linux-ide.org
-E: andre@aslab.com
-E: andre@suse.com
+E: andre@linuxdiskcert.org
 W: http://www.linux-ide.org/
+W: http://www.linuxdiskcert.org/
 D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
 D: Active-ATA-Chipset maddness..........
-D: Ultra DMA 100/66/33
-D: ATA-Disconnect
+D: Ultra DMA 133/100/66/33 w/48-bit Addressing
+D: ATA-Disconnect, ATA-TCQ
 D: ATA-Smart Kernel Daemon
+D: Serial ATA
+D: ATA Command Block and Taskfile
 S: Linux ATA Development (LAD)
 S: Concord, CA
-S: ASL, Inc. 1-877-ASL-3535
-S: 1757 Houret Court, Milpitas, CA 95035
-S: SuSE Linux, Inc.
-S: 580 Second Street, Suite 210  Oakland, CA  94607
-S: USA
 
 N: Jochen Hein
 E: jochen@jochen.org
@@ -2132,6 +2136,10 @@
 S: Fullarton 5063
 S: South Australia
 
+N. Wolfgang Muees
+E: wmues@nexgo.de
+D: Auerswald USB driver
+
 N: Ian A. Murdock
 E: imurdock@gnu.ai.mit.edu
 D: Creator of Debian distribution
@@ -2515,6 +2523,7 @@
 
 N: Thiago Berlitz Rondon
 E: maluco@mileniumnet.com.br
+W: http://vivaldi.linuxms.com.br/~maluco
 D: Miscellaneous kernel hacker
 S: R. Anhanguera, 1487 - Ipiranga
 S: 79080-740 - Campo Grande - Mato Grosso do Sul
diff -urN linux-2.4.19-pre2/Documentation/Changes linux-2.4.19-pre3/Documentation/Changes
--- linux-2.4.19-pre2/Documentation/Changes	Mon Mar 11 14:13:07 2002
+++ linux-2.4.19-pre3/Documentation/Changes	Mon Mar 11 14:13:24 2002
@@ -55,7 +55,7 @@
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
-o  reiserfsprogs          3.x.0j                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.x.1b                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -326,7 +326,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0j.tar.gz>
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0b.tar.gz>
 
 LVM toolset
 -----------
diff -urN linux-2.4.19-pre2/Documentation/Configure.help linux-2.4.19-pre3/Documentation/Configure.help
--- linux-2.4.19-pre2/Documentation/Configure.help	Mon Mar 11 14:13:08 2002
+++ linux-2.4.19-pre3/Documentation/Configure.help	Mon Mar 11 14:13:24 2002
@@ -13035,9 +13035,10 @@
 
 USB Compaq iPAQ Driver
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ running
-  Windows CE 3.0 using a USB autosync cable. For information on using
-  the driver, read <file:Documentation/usb/usb-serial.txt>.
+  Say Y here if you want to connect to your Compaq iPAQ or HP Jornada
+  548/568 running Windows CE 3.0 or PocketPC 2002 using a USB
+  cradle/cable. For information on using the driver,
+  read <file:Documentation/usb/usb-serial.txt>.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -13671,6 +13672,16 @@
   The module will be called rio500.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB Auerswald ISDN device support
+CONFIG_USB_AUERSWALD
+  Say Y here if you want to connect an Auerswald USB ISDN Device
+  to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 D-Link DSB-R100 FM radio support
 CONFIG_USB_DSBR
   Say Y here if you want to connect this type of radio to your
@@ -17666,8 +17677,12 @@
   ranging from a warning message on the console, to halting the machine.
   Your processor must be a Pentium or newer to support this - check the 
   flags in /proc/cpuinfo for mce.  Note that some older Pentium systems
-  have a design flaw which leads to false MCE events - for these and
-  old non-MCE processors (386, 486), say N.  Otherwise say Y.
+  have a design flaw which leads to false MCE events - hence MCE is
+  disabled on all P5 processors, unless explicitly enabled with "mce"
+  as a boot argument.  Similarly, if MCE is built in and creates a
+  problem on some new non-standard machine, you can boot with "nomce" 
+  to disable it.  MCE support simply ignores non-MCE processors like
+  the 386 and 486, so nearly everyone can say Y here.
 
 Toshiba Laptop support
 CONFIG_TOSHIBA
diff -urN linux-2.4.19-pre2/Documentation/DocBook/kernel-locking.tmpl linux-2.4.19-pre3/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.19-pre2/Documentation/DocBook/kernel-locking.tmpl	Sat May 19 17:43:05 2001
+++ linux-2.4.19-pre3/Documentation/DocBook/kernel-locking.tmpl	Mon Mar 11 14:13:24 2002
@@ -788,8 +788,18 @@
     </para>
 
     <para>
-      Note that the atomic operations are defined to act as both
-      read and write barriers on all platforms.
+      Note that the atomic operations do in general not act as memory
+      barriers. Instead you can insert a memory barrier before or
+      after <function>atomic_inc()</function> or
+      <function>atomic_dec()</function> by inserting
+      <function>smp_mb__before_atomic_inc()</function>,
+      <function>smp_mb__after_atomic_inc()</function>,
+      <function>smp_mb__before_atomic_dec()</function> or
+      <function>smp_mb__after_atomic_dec()</function>
+      respectively. The advantage of using those macros instead of
+      <function>smp_mb()</function> is, that they are cheaper on some
+      platforms.    
+      <!-- Sebastian Wilhelmi <seppi@seppi.de> 2002-03-04 -->
     </para>
    </sect1>
 
diff -urN linux-2.4.19-pre2/Documentation/cachetlb.txt linux-2.4.19-pre3/Documentation/cachetlb.txt
--- linux-2.4.19-pre2/Documentation/cachetlb.txt	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre3/Documentation/cachetlb.txt	Mon Mar 11 14:13:24 2002
@@ -339,7 +339,18 @@
 	If the icache does not snoop stores then this routine will need
 	to flush it.
 
+  void flush_icache_user_range(struct vm_area_struct *vma,
+			struct page *page, unsigned long addr, int len)
+	This is called when the kernel stores into addresses that are
+	part of the address space of a user process (which may be some
+	other process than the current process).  The addr argument
+	gives the virtual address in that process's address space,
+	page is the page which is being modified, and len indicates
+	how many bytes have been modified.  The modified region must
+	not cross a page boundary.  Currently this is only called from
+	kernel/ptrace.c.
+
   void flush_icache_page(struct vm_area_struct *vma, struct page *page)
-	All the functionality of flush_icache_page can be implemented in
-	flush_dcache_page and update_mmu_cache. In 2.5 the hope is to
-	remove this interface completely.
+	This is called when a page-cache page is about to be mapped
+	into a user process' address space.  It offers an opportunity
+	for a port to ensure d-cache/i-cache coherency if necessary.
diff -urN linux-2.4.19-pre2/Documentation/networking/3c359.txt linux-2.4.19-pre3/Documentation/networking/3c359.txt
--- linux-2.4.19-pre2/Documentation/networking/3c359.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/Documentation/networking/3c359.txt	Mon Mar 11 14:13:24 2002
@@ -0,0 +1,58 @@
+
+3COM PCI TOKEN LINK VELOCITY XL TOKEN RING CARDS README
+
+Release 0.9.0 - Release   
+	Jul 17th 2000 Mike Phillips 
+
+	1.2.0 - Final
+	Feb 17th 2002 Mike Phillips 
+	Updated for submission to the 2.4.x kernel.
+
+Thanks:
+	Terry Murphy from 3Com for tech docs and support,
+	Adam D. Ligas for testing the driver.
+ 
+Note:
+	This driver will NOT work with the 3C339 Token Ring cards, you need
+to use the tms380 driver instead.
+
+Options:
+
+The driver accepts three options: ringspeed, pkt_buf_sz and message_level.
+
+These options can be specified differently for each card found. 
+
+ringspeed:  Has one of three settings 0 (default), 4 or 16.  0 will 
+make the card autosense the ringspeed and join at the appropriate speed, 
+this will be the default option for most people.  4 or 16 allow you to 
+explicitly force the card to operate at a certain speed.  The card will fail 
+if you try to insert it at the wrong speed. (Although some hubs will allow 
+this so be *very* careful).  The main purpose for explicitly setting the ring
+speed is for when the card is first on the ring.  In autosense mode, if the card
+cannot detect any active monitors on the ring it will open at the same speed as
+its last opening. This can be hazardous if this speed does not match the speed
+you want the ring to operate at.  
+
+pkt_buf_sz:  This is this initial receive buffer allocation size.  This will
+default to 4096 if no value is entered. You may increase performance of the 
+driver by setting this to a value larger than the network packet size, although
+the driver now re-sizes buffers based on MTU settings as well. 
+
+message_level: Controls level of messages created by the driver. Defaults to 0:
+which only displays start-up and critical messages.  Presently any non-zero 
+value will display all soft messages as well.  NB This does not turn 
+debuging messages on, that must be done by modified the source code.
+
+Variable MTU size:
+
+The driver can handle a MTU size upto either 4500 or 18000 depending upon 
+ring speed.  The driver also changes the size of the receive buffers as part
+of the mtu re-sizing, so if you set mtu = 18000, you will need to be able
+to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring 
+position = 296,000 bytes of memory space, plus of course anything 
+necessary for the tx sk_buff's.  Remember this is per card, so if you are
+building routers, gateway's etc, you could start to use a lot of memory
+real fast.
+
+2/17/02 Mike Phillips
+
diff -urN linux-2.4.19-pre2/Documentation/networking/ppp_generic.txt linux-2.4.19-pre3/Documentation/networking/ppp_generic.txt
--- linux-2.4.19-pre2/Documentation/networking/ppp_generic.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/Documentation/networking/ppp_generic.txt	Mon Mar 11 14:13:24 2002
@@ -0,0 +1,432 @@
+		PPP Generic Driver and Channel Interface
+		----------------------------------------
+
+			    Paul Mackerras
+			   paulus@samba.org
+			      7 Feb 2002
+
+The generic PPP driver in linux-2.4 provides an implementation of the
+functionality which is of use in any PPP implementation, including:
+
+* the network interface unit (ppp0 etc.)
+* the interface to the networking code
+* PPP multilink: splitting datagrams between multiple links, and
+  ordering and combining received fragments
+* the interface to pppd, via a /dev/ppp character device
+* packet compression and decompression
+* TCP/IP header compression and decompression
+* detecting network traffic for demand dialling and for idle timeouts
+* simple packet filtering
+
+For sending and receiving PPP frames, the generic PPP driver calls on
+the services of PPP `channels'.  A PPP channel encapsulates a
+mechanism for transporting PPP frames from one machine to another.  A
+PPP channel implementation can be arbitrarily complex internally but
+has a very simple interface with the generic PPP code: it merely has
+to be able to send PPP frames, receive PPP frames, and optionally
+handle ioctl requests.  Currently there are PPP channel
+implementations for asynchronous serial ports, synchronous serial
+ports, and for PPP over ethernet.
+
+This architecture makes it possible to implement PPP multilink in a
+natural and straightforward way, by allowing more than one channel to
+be linked to each ppp network interface unit.  The generic layer is
+responsible for splitting datagrams on transmit and recombining them
+on receive.
+
+
+PPP channel API
+---------------
+
+See include/linux/ppp_channel.h for the declaration of the types and
+functions used to communicate between the generic PPP layer and PPP
+channels.
+
+Each channel has to provide two functions to the generic PPP layer,
+via the ppp_channel.ops pointer:
+
+* start_xmit() is called by the generic layer when it has a frame to
+  send.  The channel has the option of rejecting the frame for
+  flow-control reasons.  In this case, start_xmit() should return 0
+  and the channel should call the ppp_output_wakeup() function at a
+  later time when it can accept frames again, and the generic layer
+  will then attempt to retransmit the rejected frame(s).  If the frame
+  is accepted, the start_xmit() function should return 1.
+
+* ioctl() provides an interface which can be used by a user-space
+  program to control aspects of the channel's behaviour.  This
+  procedure will be called when a user-space program does an ioctl
+  system call on an instance of /dev/ppp which is bound to the
+  channel.  (Usually it would only be pppd which would do this.)
+
+The generic PPP layer provides seven functions to channels:
+
+* ppp_register_channel() is called when a channel has been created, to
+  notify the PPP generic layer of its presence.  For example, setting
+  a serial port to the PPPDISC line discipline causes the ppp_async
+  channel code to call this function.
+
+* ppp_unregister_channel() is called when a channel is to be
+  destroyed.  For example, the ppp_async channel code calls this when
+  a hangup is detected on the serial port.
+
+* ppp_output_wakeup() is called by a channel when it has previously
+  rejected a call to its start_xmit function, and can now accept more
+  packets.
+
+* ppp_input() is called by a channel when it has received a complete
+  PPP frame.
+
+* ppp_input_error() is called by a channel when it has detected that a
+  frame has been lost or dropped (for example, because of a FCS (frame
+  check sequence) error).
+
+* ppp_channel_index() returns the channel index assigned by the PPP
+  generic layer to this channel.  The channel should provide some way
+  (e.g. an ioctl) to transmit this back to user-space, as user-space
+  will need it to attach an instance of /dev/ppp to this channel.
+
+* ppp_unit_number() returns the unit number of the ppp network
+  interface to which this channel is connected, or -1 if the channel
+  is not connected.
+
+Connecting a channel to the ppp generic layer is initiated from the
+channel code, rather than from the generic layer.  The channel is
+expected to have some way for a user-level process to control it
+independently of the ppp generic layer.  For example, with the
+ppp_async channel, this is provided by the file descriptor to the
+serial port.
+
+Generally a user-level process will initialize the underlying
+communications medium and prepare it to do PPP.  For example, with an
+async tty, this can involve setting the tty speed and modes, issuing
+modem commands, and then going through some sort of dialog with the
+remote system to invoke PPP service there.  We refer to this process
+as `discovery'.  Then the user-level process tells the medium to
+become a PPP channel and register itself with the generic PPP layer.
+The channel then has to report the channel number assigned to it back
+to the user-level process.  From that point, the PPP negotiation code
+in the PPP daemon (pppd) can take over and perform the PPP
+negotiation, accessing the channel through the /dev/ppp interface.
+
+At the interface to the PPP generic layer, PPP frames are stored in
+skbuff structures and start with the two-byte PPP protocol number.
+The frame does *not* include the 0xff `address' byte or the 0x03
+`control' byte that are optionally used in async PPP.  Nor is there
+any escaping of control characters, nor are there any FCS or framing
+characters included.  That is all the responsibility of the channel
+code, if it is needed for the particular medium.  That is, the skbuffs
+presented to the start_xmit() function contain only the 2-byte
+protocol number and the data, and the skbuffs presented to ppp_input()
+must be in the same format.
+
+The channel must provide an instance of a ppp_channel struct to
+represent the channel.  The channel is free to use the `private' field
+however it wishes.  The channel should initialize the `mtu' and
+`hdrlen' fields before calling ppp_register_channel() and not change
+them until after ppp_unregister_channel() returns.  The `mtu' field
+represents the maximum size of the data part of the PPP frames, that
+is, it does not include the 2-byte protocol number.
+
+If the channel needs some headroom in the skbuffs presented to it for
+transmission (i.e., some space free in the skbuff data area before the
+start of the PPP frame), it should set the `hdrlen' field of the
+ppp_channel struct to the amount of headroom required.  The generic
+PPP layer will attempt to provide that much headroom but the channel
+should still check if there is sufficient headroom and copy the skbuff
+if there isn't.
+
+On the input side, channels should ideally provide at least 2 bytes of
+headroom in the skbuffs presented to ppp_input().  The generic PPP
+code does not require this but will be more efficient if this is done.
+
+
+Buffering and flow control
+--------------------------
+
+The generic PPP layer has been designed to minimize the amount of data
+that it buffers in the transmit direction.  It maintains a queue of
+transmit packets for the PPP unit (network interface device) plus a
+queue of transmit packets for each attached channel.  Normally the
+transmit queue for the unit will contain at most one packet; the
+exceptions are when pppd sends packets by writing to /dev/ppp, and
+when the core networking code calls the generic layer's start_xmit()
+function with the queue stopped, i.e. when the generic layer has
+called netif_stop_queue(), which only happens on a transmit timeout.
+The start_xmit function always accepts and queues the packet which it
+is asked to transmit.
+
+Transmit packets are dequeued from the PPP unit transmit queue and
+then subjected to TCP/IP header compression and packet compression
+(Deflate or BSD-Compress compression), as appropriate.  After this
+point the packets can no longer be reordered, as the decompression
+algorithms rely on receiving compressed packets in the same order that
+they were generated.
+
+If multilink is not in use, this packet is then passed to the attached
+channel's start_xmit() function.  If the channel refuses to take
+the packet, the generic layer saves it for later transmission.  The
+generic layer will call the channel's start_xmit() function again
+when the channel calls  ppp_output_wakeup() or when the core
+networking code calls the generic layer's start_xmit() function
+again.  The generic layer contains no timeout and retransmission
+logic; it relies on the core networking code for that.
+
+If multilink is in use, the generic layer divides the packet into one
+or more fragments and puts a multilink header on each fragment.  It
+decides how many fragments to use based on the length of the packet
+and the number of channels which are potentially able to accept a
+fragment at the moment.  A channel is potentially able to accept a
+fragment if it doesn't have any fragments currently queued up for it
+to transmit.  The channel may still refuse a fragment; in this case
+the fragment is queued up for the channel to transmit later.  This
+scheme has the effect that more fragments are given to higher-
+bandwidth channels.  It also means that under light load, the generic
+layer will tend to fragment large packets across all the channels,
+thus reducing latency, while under heavy load, packets will tend to be
+transmitted as single fragments, thus reducing the overhead of
+fragmentation.
+
+
+SMP safety
+----------
+
+The PPP generic layer has been designed to be SMP-safe.  Locks are
+used around accesses to the internal data structures where necessary
+to ensure their integrity.  As part of this, the generic layer
+requires that the channels adhere to certain requirements and in turn
+provides certain guarantees to the channels.  Essentially the channels
+are required to provide the appropriate locking on the ppp_channel
+structures that form the basis of the communication between the
+channel and the generic layer.  This is because the channel provides
+the storage for the ppp_channel structure, and so the channel is
+required to provide the guarantee that this storage exists and is
+valid at the appropriate times.
+
+The generic layer requires these guarantees from the channel:
+
+* The ppp_channel object must exist from the time that
+  ppp_register_channel() is called until after the call to
+  ppp_unregister_channel() returns.
+
+* No thread may be in a call to any of ppp_input(), ppp_input_error(),
+  ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a
+  channel at the time that ppp_unregister_channel() is called for that
+  channel.
+
+* ppp_register_channel() and ppp_unregister_channel() must be called
+  from process context, not interrupt or softirq/BH context.
+
+* The remaining generic layer functions may be called at softirq/BH
+  level but must not be called from a hardware interrupt handler.
+
+* The generic layer may call the channel start_xmit() function at
+  softirq/BH level but will not call it at interrupt level.  Thus the
+  start_xmit() function may not block.
+
+* The generic layer will only call the channel ioctl() function in
+  process context.
+
+The generic layer provides these guarantees to the channels:
+
+* The generic layer will not call the start_xmit() function for a
+  channel while any thread is already executing in that function for
+  that channel.
+
+* The generic layer will not call the ioctl() function for a channel
+  while any thread is already executing in that function for that
+  channel.
+
+* By the time a call to ppp_unregister_channel() returns, no thread
+  will be executing in a call from the generic layer to that channel's
+  start_xmit() or ioctl() function, and the generic layer will not
+  call either of those functions subsequently.
+
+
+Interface to pppd
+-----------------
+
+The PPP generic layer exports a character device interface called
+/dev/ppp.  This is used by pppd to control PPP interface units and
+channels.  Although there is only one /dev/ppp, each open instance of
+/dev/ppp acts independently and can be attached either to a PPP unit
+or a PPP channel.  This is achieved using the file->private_data field
+to point to a separate object for each open instance of /dev/ppp.  In
+this way an effect similar to Solaris' clone open is obtained,
+allowing us to control an arbitrary number of PPP interfaces and
+channels without having to fill up /dev with hundreds of device names.
+
+When /dev/ppp is opened, a new instance is created which is initially
+unattached.  Using an ioctl call, it can then be attached to an
+existing unit, attached to a newly-created unit, or attached to an
+existing channel.  An instance attached to a unit can be used to send
+and receive PPP control frames, using the read() and write() system
+calls, along with poll() if necessary.  Similarly, an instance
+attached to a channel can be used to send and receive PPP frames on
+that channel.
+
+In multilink terms, the unit represents the bundle, while the channels
+represent the individual physical links.  Thus, a PPP frame sent by a
+write to the unit (i.e., to an instance of /dev/ppp attached to the
+unit) will be subject to bundle-level compression and to fragmentation
+across the individual links (if multilink is in use).  In contrast, a
+PPP frame sent by a write to the channel will be sent as-is on that
+channel, without any multilink header.
+
+A channel is not initially attached to any unit.  In this state it can
+be used for PPP negotiation but not for the transfer of data packets.
+It can then be connected to a PPP unit with an ioctl call, which
+makes it available to send and receive data packets for that unit.
+
+The ioctl calls which are available on an instance of /dev/ppp depend
+on whether it is unattached, attached to a PPP interface, or attached
+to a PPP channel.  The ioctl calls which are available on an
+unattached instance are:
+
+* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp
+  instance the "owner" of the interface.  The argument should point to
+  an int which is the desired unit number if >= 0, or -1 to assign the
+  lowest unused unit number.  Being the owner of the interface means
+  that the interface will be shut down if this instance of /dev/ppp is
+  closed.
+
+* PPPIOCATTACH attaches this instance to an existing PPP interface.
+  The argument should point to an int containing the unit number.
+  This does not make this instance the owner of the PPP interface.
+
+* PPPIOCATTCHAN attaches this instance to an existing PPP channel.
+  The argument should point to an int containing the channel number.
+
+The ioctl calls available on an instance of /dev/ppp attached to a
+channel are:
+
+* PPPIOCDETACH detaches the instance from the channel.  This ioctl is
+  deprecated since the same effect can be achieved by closing the
+  instance.  In order to prevent possible races this ioctl will fail
+  with an EINVAL error if more than one file descriptor refers to this
+  instance (i.e. as a result of dup(), dup2() or fork()).
+
+* PPPIOCCONNECT connects this channel to a PPP interface.  The
+  argument should point to an int containing the interface unit
+  number.  It will return an EINVAL error if the channel is already
+  connected to an interface, or ENXIO if the requested interface does
+  not exist.
+
+* PPPIOCDISCONN disconnects this channel from the PPP interface that
+  it is connected to.  It will return an EINVAL error if the channel
+  is not connected to an interface.
+
+* All other ioctl commands are passed to the channel ioctl() function.
+
+The ioctl calls that are available on an instance that is attached to
+an interface unit are:
+
+* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface.
+  The argument should point to an int containing the new MRU value.
+
+* PPPIOCSFLAGS sets flags which control the operation of the
+  interface.  The argument should be a pointer to an int containing
+  the new flags value.  The bits in the flags value that can be set
+  are:
+	SC_COMP_TCP		enable transmit TCP header compression
+	SC_NO_TCP_CCID		disable connection-id compression for
+				TCP header compression
+	SC_REJ_COMP_TCP		disable receive TCP header decompression
+	SC_CCP_OPEN		Compression Control Protocol (CCP) is
+				open, so inspect CCP packets
+	SC_CCP_UP		CCP is up, may (de)compress packets
+	SC_LOOP_TRAFFIC		send IP traffic to pppd
+	SC_MULTILINK		enable PPP multilink fragmentation on
+				transmitted packets
+	SC_MP_SHORTSEQ		expect short multilink sequence
+				numbers on received multilink fragments
+	SC_MP_XSHORTSEQ		transmit short multilink sequence nos.
+
+  The values of these flags are defined in <linux/if_ppp.h>.  Note
+  that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and
+  SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option
+  is not selected.
+
+* PPPIOCGFLAGS returns the value of the status/control flags for the
+  interface unit.  The argument should point to an int where the ioctl
+  will store the flags value.  As well as the values listed above for
+  PPPIOCSFLAGS, the following bits may be set in the returned value:
+	SC_COMP_RUN		CCP compressor is running
+	SC_DECOMP_RUN		CCP decompressor is running
+	SC_DC_ERROR		CCP decompressor detected non-fatal error
+	SC_DC_FERROR		CCP decompressor detected fatal error
+
+* PPPIOCSCOMPRESS sets the parameters for packet compression or
+  decompression.  The argument should point to a ppp_option_data
+  structure (defined in <linux/if_ppp.h>), which contains a
+  pointer/length pair which should describe a block of memory
+  containing a CCP option specifying a compression method and its
+  parameters.  The ppp_option_data struct also contains a `transmit'
+  field.  If this is 0, the ioctl will affect the receive path,
+  otherwise the transmit path.
+
+* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit
+  number of this interface unit.
+
+* PPPIOCSDEBUG sets the debug flags for the interface to the value in
+  the int pointed to by the argument.  Only the least significant bit
+  is used; if this is 1 the generic layer will print some debug
+  messages during its operation.  This is only intended for debugging
+  the generic PPP layer code; it is generally not helpful for working
+  out why a PPP connection is failing.
+
+* PPPIOCGDEBUG returns the debug flags for the interface in the int
+  pointed to by the argument.
+
+* PPPIOCGIDLE returns the time, in seconds, since the last data
+  packets were sent and received.  The argument should point to a
+  ppp_idle structure (defined in <linux/ppp_defs.h>).  If the
+  CONFIG_PPP_FILTER option is enabled, the set of packets which reset
+  the transmit and receive idle timers is restricted to those which
+  pass the `active' packet filter.
+
+* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
+  number of connection slots) for the TCP header compressor and
+  decompressor.  The lower 16 bits of the int pointed to by the
+  argument specify the maximum connection-ID for the compressor.  If
+  the upper 16 bits of that int are non-zero, they specify the maximum
+  connection-ID for the decompressor, otherwise the decompressor's
+  maximum connection-ID is set to 15.
+
+* PPPIOCSNPMODE sets the network-protocol mode for a given network
+  protocol.  The argument should point to an npioctl struct (defined
+  in <linux/if_ppp.h>).  The `protocol' field gives the PPP protocol
+  number for the protocol to be affected, and the `mode' field
+  specifies what to do with packets for that protocol:
+
+	NPMODE_PASS	normal operation, transmit and receive packets
+	NPMODE_DROP	silently drop packets for this protocol
+	NPMODE_ERROR	drop packets and return an error on transmit
+	NPMODE_QUEUE	queue up packets for transmit, drop received
+			packets
+
+  At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as
+  NPMODE_DROP.
+
+* PPPIOCGNPMODE returns the network-protocol mode for a given
+  protocol.  The argument should point to an npioctl struct with the
+  `protocol' field set to the PPP protocol number for the protocol of
+  interest.  On return the `mode' field will be set to the network-
+  protocol mode for that protocol.
+
+* PPPIOCSPASS and PPPIOCSACTIVE set the `pass' and `active' packet
+  filters.  These ioctls are only available if the CONFIG_PPP_FILTER
+  option is selected.  The argument should point to a sock_fprog
+  structure (defined in <linux/filter.h>) containing the compiled BPF
+  instructions for the filter.  Packets are dropped if they fail the
+  `pass' filter; otherwise, if they fail the `active' filter they are
+  passed but they do not reset the transmit or receive idle timer.
+
+* PPPIOCSMRRU enables or disables multilink processing for received
+  packets and sets the multilink MRRU (maximum reconstructed receive
+  unit).  The argument should point to an int containing the new MRRU
+  value.  If the MRRU value is 0, processing of received multilink
+  fragments is disabled.  This ioctl is only available if the
+  CONFIG_PPP_MULTILINK option is selected.
+
+Last modified: 7-feb-2002
diff -urN linux-2.4.19-pre2/Documentation/usb/auerswald.txt linux-2.4.19-pre3/Documentation/usb/auerswald.txt
--- linux-2.4.19-pre2/Documentation/usb/auerswald.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/Documentation/usb/auerswald.txt	Mon Mar 11 14:13:24 2002
@@ -0,0 +1,30 @@
+		Auerswald USB kernel driver
+		===========================
+
+What is it? What can I do with it?
+==================================
+The auerswald USB kernel driver connects your linux 2.4.x
+system to the auerswald usb-enabled devices.
+
+There are two types of auerswald usb devices:
+a) small PBX systems (ISDN)
+b) COMfort system telephones (ISDN)
+
+The driver installation creates the devices
+/dev/usb/auer0..15. These devices carry a vendor-
+specific protocol. You may run all auerswald java
+software on it. The java software needs a native
+library "libAuerUsbJNINative.so" installed on
+your system. This library is available from
+auerswald and shipped as part of the java software.
+
+You may create the devices with:
+	mknod -m 666 /dev/usb/auer0 c 180 112
+	...
+	mknod -m 666 /dev/usb/auer15 c 180 127
+
+Future plans
+============
+- Connection to ISDN4LINUX (the hisax interface)
+
+The maintainer of this driver is wmues@nexgo.de
diff -urN linux-2.4.19-pre2/Documentation/usb/usb-serial.txt linux-2.4.19-pre3/Documentation/usb/usb-serial.txt
--- linux-2.4.19-pre2/Documentation/usb/usb-serial.txt	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre3/Documentation/usb/usb-serial.txt	Mon Mar 11 14:13:25 2002
@@ -95,12 +95,13 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ driver
+Compaq iPAQ and HP Jornada driver
 
-  This driver can be used to connect to Compaq iPAQ PDAs running
-  Windows CE 3.0 using a USB autosync cable. It has been tested only on
-  the Compaq H3135. It should work with the H3600 and later models too.
-  It may work with other CE based handhelds as well.
+  This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs
+  running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
+  has been tested only on the Compaq H3135, but is rumoured to work on
+  with the H3600 and later models as well as the Jornada 548 and 568.
+  With minor modifications, it may work for other CE based handhelds too.
 
   The driver presents a serial interface (usually on /dev/ttyUSB0) over
   which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
@@ -109,11 +110,14 @@
   kbytes/sec for download/upload to the iPAQ.
 
   The driver works intermittently with the usb-uhci driver but quite
-  reliably with the uhci driver. Make sure you have the right driver
-  loaded - usb-uhci is often the default.
+  reliably with the uhci driver. However, performance is much better
+  with usb-uhci. It does not seem to work with ohci at all.
 
   You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
-  A ppp script like the one below may be used:
+  A ppp script like the one below should be kept in the file
+  /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no
+  options in /etc/ppp/options or ~/.ppprc which conflict with the ones
+  given below.
 
 	#!/bin/bash
 
@@ -133,7 +137,7 @@
   On connecting the cable, you should see the usual "Device Connected",
   "User Authenticated" messages flash by on your iPAQ. Once connected,
   you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
-  and other synce utilities from the Linux side. Remember to enable IP
+  and xcerdisp, synce utilities from the Linux side. Remember to enable IP
   forwarding. 
 
   To use Pocket IE, follow the instructions given at
diff -urN linux-2.4.19-pre2/Documentation/watchdog-api.txt linux-2.4.19-pre3/Documentation/watchdog-api.txt
--- linux-2.4.19-pre2/Documentation/watchdog-api.txt	Mon Mar 11 14:13:09 2002
+++ linux-2.4.19-pre3/Documentation/watchdog-api.txt	Mon Mar 11 14:13:25 2002
@@ -69,9 +69,7 @@
 
 The ioctl API:
 
-Some drivers also support an ioctl API.  I belive this API was first
-used in the Berkshire PC Watchdog driver and has been adopted by the
-other drivers.  
+All conforming drivers also support an ioctl API.
 
 Pinging the watchdog using an ioctl:
 
@@ -111,9 +109,9 @@
 
 Envinronmental monitoring:
 
-Some watchdog drivers can return more information about the system,
+All watchdog drivers are required return more information about the system,
 some do temperature, fan and power level monitoring, some can tell you
-the reason for the last reebot of the system.  The GETSUPPORT ioctl is
+the reason for the last reboot of the system.  The GETSUPPORT ioctl is
 available to ask what the device can do:
 
 	struct watchdog_info ident;
@@ -130,17 +128,44 @@
 return.   [FIXME -- Is this correct?]
 
 	WDIOF_OVERHEAT		Reset due to CPU overheat
+
+The machine was last rebooted by the watchdog because the thermal limit was
+exceeded
+
 	WDIOF_FANFAULT		Fan failed
+
+A system fan monitored by the watchdog card has failed
+
 	WDIOF_EXTERN1		External relay 1
+
+External monitoring relay/source 1 was triggered. Controllers intended for
+real world applications include external monitoring pins that will trigger
+a reset.
+
 	WDIOF_EXTERN2		External relay 2
+
+External monitoring relay/source 2 was triggered
+
 	WDIOF_POWERUNDER	Power bad/power fault
+
+The machine is showing an undervoltage status
+
 	WDIOF_CARDRESET		Card previously reset the CPU
+
+The last reboot was caused by the watchdog card
+
 	WDIOF_POWEROVER		Power over voltage
+
+The machine is showing an overvoltage status. Note that if one level is
+under and one over both bits will be set - this may seem odd but makes
+sense.
+
 	WDIOF_KEEPALIVEPING	Keep alive ping reply
+
+The watchdog saw a keepalive ping since it was last queried.
+
 	WDIOF_SETTIMEOUT	Can set/get the timeout
 
-[FIXME -- Can somebody explain what the flags mean in more detail,
-especially KEEPALIVEPING?]
 
 For those drivers that return any bits set in the option field, the
 GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current
@@ -219,7 +244,7 @@
 
 i810-tco.c -- Intel 810 chipset
 
-	Also has support for a lot of other i810 stuff, but the
+	Also has support for a lot of other i8x0 stuff, but the
 	watchdog is one of the things.
 
 	The timeout is set using the module parameter "i810_margin",
@@ -292,6 +317,18 @@
 
 	No bits set in GETSUPPORT
 
+scx200.c -- National SCx200 CPUs
+
+	Not in the kernel yet.
+
+	The timeout is set using a module parameter "margin" which
+	defaults to 60 seconds.  The timeout can also be set using
+	SETTIMEOUT and read using GETTIMEOUT.
+
+	Supports a module parameter "nowayout" that is initialized
+	with the value of CONFIG_WATCHDOG_NOWAYOUT.  Also supports the
+	magic character 'V' handling.
+
 shwdt.c -- SuperH 3/4 processors
 
 	[FIXME -- I'm unable to tell what the timeout is]
@@ -329,10 +366,9 @@
 
 	Supports CONFIG_WATCHDOG_NOWAYOUT
 
-	GETSUPPORT returns with a lot of bits set, it seems that the
-	driver can check for overheating, power failure, fan failure
-	and a two external relay inputs.  GETSTATUS can be used to
-	read these flags.
+	GETSUPPORT returns with bits set depending on the actual
+	card. The WDT501 supports a lot of external monitoring, the
+	WDT500 much less.
 
 wdt285.c -- Footbridge watchdog
 
@@ -352,14 +388,3 @@
 
 	Does not support any ioctls at all.
 
-scx200.c -- National SCx200 CPUs
-
-	Not in the kernel yet.
-
-	The timeout is set using a module parameter "margin" which
-	defaults to 60 seconds.  The timeout can also be set using
-	SETTIMEOUT and read using GETTIMEOUT.
-
-	Supports a module parameter "nowayout" that is initialized
-	with the value of CONFIG_WATCHDOG_NOWAYOUT.  Also supports the
-	magic character 'V' handling.
diff -urN linux-2.4.19-pre2/MAINTAINERS linux-2.4.19-pre3/MAINTAINERS
--- linux-2.4.19-pre2/MAINTAINERS	Mon Mar 11 14:13:09 2002
+++ linux-2.4.19-pre3/MAINTAINERS	Mon Mar 11 14:13:25 2002
@@ -69,6 +69,14 @@
 			it has been replaced by a better system and you
 			should be using that.
 
+3C359 NETWORK DRIVER
+P:	Mike Phillips
+M:	mikep@linuxtr.net
+L:	linux-net@vger.rutgers.edu
+L:	linux-tr@linuxtr.net
+W:	http://www.linuxtr.net
+S:	Maintained
+
 3C501 NETWORK DRIVER
 P:	Alan Cox
 M:	alan@the.3c501.cabal.tm
@@ -1584,6 +1592,13 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Supported
 
+USB AUERSWALD DRIVER
+P:	Wolfgang Muees
+M:	wmues@nexgo.de
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
 USB BLUETOOTH DRIVER
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
@@ -1599,6 +1614,12 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB EHCI DRIVER
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
 USB HID/HIDBP/INPUT DRIVERS
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
@@ -1615,8 +1636,8 @@
 S:	Maintained
 
 USB KAWASAKI LSI DRIVER
-P:	Brad Hards
-M:	bradh@frogmouth.net
+P:	Oliver Neukum
+M:	drivers@neukum.org
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
@@ -1727,6 +1748,12 @@
 W:	http://usb.in.tum.de
 S:	Maintained
 	
+USB "USBNET" DRIVER
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
 VFAT FILESYSTEM:
 P:	Gordon Chaffee
 M:	chaffee@cs.berkeley.edu
diff -urN linux-2.4.19-pre2/Makefile linux-2.4.19-pre3/Makefile
--- linux-2.4.19-pre2/Makefile	Mon Mar 11 14:13:09 2002
+++ linux-2.4.19-pre3/Makefile	Mon Mar 11 14:13:25 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 19
-EXTRAVERSION = -pre2
+EXTRAVERSION = -pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.19-pre2/Rules.make linux-2.4.19-pre3/Rules.make
--- linux-2.4.19-pre2/Rules.make	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre3/Rules.make	Mon Mar 11 14:13:25 2002
@@ -50,10 +50,10 @@
 #
 
 %.s: %.c
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@
 
 %.i: %.c
-	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@
+	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@
 
 %.o: %.c
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $<
diff -urN linux-2.4.19-pre2/arch/alpha/kernel/entry.S linux-2.4.19-pre3/arch/alpha/kernel/entry.S
--- linux-2.4.19-pre2/arch/alpha/kernel/entry.S	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre3/arch/alpha/kernel/entry.S	Mon Mar 11 14:13:25 2002
@@ -1148,3 +1148,4 @@
 	.quad sys_gettid
 	.quad sys_readahead
 	.quad sys_ni_syscall			/* 380, sys_security */
+	.quad sys_tkill
diff -urN linux-2.4.19-pre2/arch/alpha/kernel/signal.c linux-2.4.19-pre3/arch/alpha/kernel/signal.c
--- linux-2.4.19-pre2/arch/alpha/kernel/signal.c	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre3/arch/alpha/kernel/signal.c	Mon Mar 11 14:13:25 2002
@@ -717,9 +717,7 @@
 
 			default:
 				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 			continue;
diff -urN linux-2.4.19-pre2/arch/alpha/kernel/smp.c linux-2.4.19-pre3/arch/alpha/kernel/smp.c
--- linux-2.4.19-pre2/arch/alpha/kernel/smp.c	Mon Mar 11 14:13:10 2002
+++ linux-2.4.19-pre3/arch/alpha/kernel/smp.c	Mon Mar 11 14:13:25 2002
@@ -1079,7 +1079,8 @@
 }
 
 void
-flush_icache_page(struct vm_area_struct *vma, struct page *page)
+flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+			unsigned long addr, int len)
 {
 	struct mm_struct *mm = vma->vm_mm;
 
diff -urN linux-2.4.19-pre2/arch/arm/kernel/calls.S linux-2.4.19-pre3/arch/arm/kernel/calls.S
--- linux-2.4.19-pre2/arch/arm/kernel/calls.S	Mon Oct  8 10:39:18 2001
+++ linux-2.4.19-pre3/arch/arm/kernel/calls.S	Mon Mar 11 14:13:25 2002
@@ -236,6 +236,8 @@
 		.long	SYMBOL_NAME(sys_mincore)
 /* 220 */	.long	SYMBOL_NAME(sys_madvise)
 		.long	SYMBOL_NAME(sys_fcntl64)
+		.long	SYMBOL_NAME(sys_gettid)
+		.long	SYMBOL_NAME(sys_tkill)
 __syscall_end:
 
 		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
diff -urN linux-2.4.19-pre2/arch/arm/kernel/signal.c linux-2.4.19-pre3/arch/arm/kernel/signal.c
--- linux-2.4.19-pre2/arch/arm/kernel/signal.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/arm/kernel/signal.c	Mon Mar 11 14:13:25 2002
@@ -637,10 +637,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/cris/drivers/ethernet.c linux-2.4.19-pre3/arch/cris/drivers/ethernet.c
--- linux-2.4.19-pre2/arch/cris/drivers/ethernet.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre3/arch/cris/drivers/ethernet.c	Mon Mar 11 14:13:25 2002
@@ -1005,7 +1005,7 @@
 	int i;
 #endif
 
-	if (!led_active && jiffies > led_next_time) {
+	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
 
@@ -1297,7 +1297,7 @@
 {
 	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
 
-	if (!led_active && jiffies > led_next_time) {
+	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
 
@@ -1322,7 +1322,7 @@
 static void
 e100_clear_network_leds(unsigned long dummy)
 {
-	if (led_active && jiffies > led_next_time) {
+	if (led_active && jiffies > time_after(jiffies, led_next_time)) {
 		e100_set_network_leds(NO_NETWORK_ACTIVITY);
 
 		/* Set the earliest time we may set the LED */
diff -urN linux-2.4.19-pre2/arch/cris/drivers/ide.c linux-2.4.19-pre3/arch/cris/drivers/ide.c
--- linux-2.4.19-pre2/arch/cris/drivers/ide.c	Wed Jul  4 11:50:38 2001
+++ linux-2.4.19-pre3/arch/cris/drivers/ide.c	Mon Mar 11 14:13:25 2002
@@ -354,7 +354,7 @@
 	printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY);
 
 	h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
-	while(jiffies < h) ;
+	while(time_before(jiffies, h)) ;
 
   /* reset the dma channels we will use */
 
diff -urN linux-2.4.19-pre2/arch/cris/drivers/lpslave/e100lpslavenet.c linux-2.4.19-pre3/arch/cris/drivers/lpslave/e100lpslavenet.c
--- linux-2.4.19-pre2/arch/cris/drivers/lpslave/e100lpslavenet.c	Thu Jul 26 15:10:06 2001
+++ linux-2.4.19-pre3/arch/cris/drivers/lpslave/e100lpslavenet.c	Mon Mar 11 14:13:25 2002
@@ -310,7 +310,7 @@
 		IO_STATE(R_PAR0_CONFIG, iautofd, noninv)    |
           /* Not used in reverse direction, don't care */
 		IO_STATE(R_PAR0_CONFIG, istrb,   noninv)    |
-          /* Not connected, don't care /
+          /* Not connected, don't care */
 		IO_STATE(R_PAR0_CONFIG, iinit,   noninv)    |
           /* perror is GND and reverse wants 0, noninv */
 		IO_STATE(R_PAR0_CONFIG, iperr,   noninv)    |
diff -urN linux-2.4.19-pre2/arch/cris/kernel/entry.S linux-2.4.19-pre3/arch/cris/kernel/entry.S
--- linux-2.4.19-pre2/arch/cris/kernel/entry.S	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre3/arch/cris/kernel/entry.S	Mon Mar 11 14:13:25 2002
@@ -1013,6 +1013,7 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
+        .long SYMBOL_NAME(sys_tkill)
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -urN linux-2.4.19-pre2/arch/cris/kernel/signal.c linux-2.4.19-pre3/arch/cris/kernel/signal.c
--- linux-2.4.19-pre2/arch/cris/kernel/signal.c	Mon Oct  8 11:43:54 2001
+++ linux-2.4.19-pre3/arch/cris/kernel/signal.c	Mon Mar 11 14:13:25 2002
@@ -679,10 +679,7 @@
 
 			default:
 				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/i386/kernel/acpitable.c linux-2.4.19-pre3/arch/i386/kernel/acpitable.c
--- linux-2.4.19-pre2/arch/i386/kernel/acpitable.c	Sun Nov 11 19:15:06 2001
+++ linux-2.4.19-pre3/arch/i386/kernel/acpitable.c	Mon Mar 11 14:13:25 2002
@@ -172,40 +172,41 @@
 
 
 /*
- * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0,
+ * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
  * to map the target physical address. The problem is that set_fixmap()
  * provides a single page, and it is possible that the page is not
  * sufficient.
  * By using this area, we can map up to MAX_IO_APICS pages temporarily,
  * i.e. until the next __va_range() call.
+ *
+ * Important Safety Note:  The fixed I/O APIC page numbers are *subtracted*
+ * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
+ * count idx down while incrementing the phys address.
  */
-static __inline__ char *
+static __init char *
 __va_range(unsigned long phys, unsigned long size)
 {
-	unsigned long base, offset, mapped_size, mapped_phys = phys;
-	int idx = FIX_IO_APIC_BASE_0;
+	unsigned long base, offset, mapped_size;
+	int idx;
 
 	offset = phys & (PAGE_SIZE - 1);
 	mapped_size = PAGE_SIZE - offset;
-	set_fixmap(idx, mapped_phys);
-	base = fix_to_virt(FIX_IO_APIC_BASE_0);
+	set_fixmap(FIX_IO_APIC_BASE_END, phys);
+	base = fix_to_virt(FIX_IO_APIC_BASE_END);
+	dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size,
+		FIX_IO_APIC_BASE_END, base);
 
 	/*
 	 * Most cases can be covered by the below.
 	 */
-	if (mapped_size >= size)
-		return ((unsigned char *) base + offset);
-
-	dprintk("__va_range: mapping more than a single page, size = 0x%lx\n",
-		size);
-
-	do {
-		if (idx++ == FIX_IO_APIC_BASE_END)
+	idx = FIX_IO_APIC_BASE_END;
+	while (mapped_size < size) {
+		if (--idx < FIX_IO_APIC_BASE_0)
 			return 0;	/* cannot handle this */
-		mapped_phys = mapped_phys + PAGE_SIZE;
-		set_fixmap(idx, mapped_phys);
-		mapped_size = mapped_size + PAGE_SIZE;
-	} while (mapped_size < size);
+		phys += PAGE_SIZE;
+		set_fixmap(idx, phys);
+		mapped_size += PAGE_SIZE;
+	}
 
 	return ((unsigned char *) base + offset);
 }
@@ -267,11 +268,14 @@
 	}
 
 	for (i = 0; i < tables; i++) {
-
+		/* Map in header, then map in full table length. */
 		header = (acpi_table_header *)
 			    __va_range(saved_rsdt.entry[i],
 				       sizeof(acpi_table_header));
-
+		if (!header)
+			break;
+		header = (acpi_table_header *)
+			    __va_range(saved_rsdt.entry[i], header->length);
 		if (!header)
 			break;
 
diff -urN linux-2.4.19-pre2/arch/i386/kernel/bluesmoke.c linux-2.4.19-pre3/arch/i386/kernel/bluesmoke.c
--- linux-2.4.19-pre2/arch/i386/kernel/bluesmoke.c	Mon Mar 11 14:13:10 2002
+++ linux-2.4.19-pre3/arch/i386/kernel/bluesmoke.c	Mon Mar 11 14:13:25 2002
@@ -169,7 +169,7 @@
 	if(l&(1<<8))
 		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 	banks = l&0xff;
-	for(i=1;i<banks;i++)
+	for(i=0;i<banks;i++)
 	{
 		wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
 	}
diff -urN linux-2.4.19-pre2/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre3/arch/i386/kernel/dmi_scan.c
--- linux-2.4.19-pre2/arch/i386/kernel/dmi_scan.c	Mon Mar 11 14:13:10 2002
+++ linux-2.4.19-pre3/arch/i386/kernel/dmi_scan.c	Mon Mar 11 14:13:25 2002
@@ -9,6 +9,7 @@
 #include <linux/pm.h>
 #include <asm/keyboard.h>
 #include <asm/system.h>
+#include <linux/bootmem.h>
 
 unsigned long dmi_broken;
 int is_sony_vaio_laptop;
@@ -51,7 +52,7 @@
 	u8 *data;
 	int i=1;
 		
-	buf = ioremap(base, len);
+	buf = bt_ioremap(base, len);
 	if(buf==NULL)
 		return -1;
 
@@ -83,7 +84,7 @@
 		data+=2;
 		i++;
 	}
-	iounmap(buf);
+	bt_iounmap(buf, len);
 	return 0;
 }
 
@@ -155,7 +156,7 @@
 		return;
 	if (dmi_ident[slot])
 		return;
-	dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL);
+	dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
 	if(dmi_ident[slot])
 		strcpy(dmi_ident[slot], p);
 	else
@@ -504,6 +505,12 @@
 			MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
 			MATCH(DMI_BIOS_VERSION,"Version R2.08")
 			} },
+	{ apm_is_horked, "Dell Inspiron 2500", { /* APM crashes */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
+			MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION,"A11")
+			} },
 	{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
 			MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 			MATCH(DMI_PRODUCT_NAME, "PCG-"),
@@ -736,12 +743,9 @@
 	}
 }
 
-static int __init dmi_scan_machine(void)
+void __init dmi_scan_machine(void)
 {
 	int err = dmi_iterate(dmi_decode);
 	if(err == 0)
 		dmi_check_blacklist();
-	return err;
 }
-
-module_init(dmi_scan_machine);
diff -urN linux-2.4.19-pre2/arch/i386/kernel/entry.S linux-2.4.19-pre3/arch/i386/kernel/entry.S
--- linux-2.4.19-pre2/arch/i386/kernel/entry.S	Mon Feb 25 11:37:53 2002
+++ linux-2.4.19-pre3/arch/i386/kernel/entry.S	Mon Mar 11 14:13:25 2002
@@ -634,6 +634,7 @@
 	.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 */
+ 	.long SYMBOL_NAME(sys_tkill)
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.4.19-pre2/arch/i386/kernel/io_apic.c linux-2.4.19-pre3/arch/i386/kernel/io_apic.c
--- linux-2.4.19-pre2/arch/i386/kernel/io_apic.c	Tue Nov 13 17:28:41 2001
+++ linux-2.4.19-pre3/arch/i386/kernel/io_apic.c	Mon Mar 11 14:13:25 2002
@@ -67,7 +67,7 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int apic, int pin)
+static void __init add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
 	static int first_free_entry = NR_IRQS;
 	struct irq_pin_list *entry = irq_2_pin + irq;
@@ -85,6 +85,26 @@
 	entry->pin = pin;
 }
 
+/*
+ * Reroute an IRQ to a different pin.
+ */
+static void __init replace_pin_at_irq(unsigned int irq,
+				      int oldapic, int oldpin,
+				      int newapic, int newpin)
+{
+	struct irq_pin_list *entry = irq_2_pin + irq;
+
+	while (1) {
+		if (entry->apic == oldapic && entry->pin == oldpin) {
+			entry->apic = newapic;
+			entry->pin = newpin;
+		}
+		if (!entry->next)
+			break;
+		entry = irq_2_pin + entry->next;
+	}
+}
+
 #define __DO_ACTION(R, ACTION, FINAL)					\
 									\
 {									\
@@ -1533,6 +1553,10 @@
 		setup_ExtINT_IRQ0_pin(pin2, vector);
 		if (timer_irq_works()) {
 			printk("works.\n");
+			if (pin1 != -1)
+				replace_pin_at_irq(0, 0, pin1, 0, pin2);
+			else
+				add_pin_to_irq(0, 0, pin2);
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
 				check_nmi_watchdog();
diff -urN linux-2.4.19-pre2/arch/i386/kernel/nmi.c linux-2.4.19-pre3/arch/i386/kernel/nmi.c
--- linux-2.4.19-pre2/arch/i386/kernel/nmi.c	Thu Sep 20 20:55:24 2001
+++ linux-2.4.19-pre3/arch/i386/kernel/nmi.c	Mon Mar 11 14:13:25 2002
@@ -8,6 +8,7 @@
  *  Fixes:
  *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
  *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
  */
 
 #include <linux/config.h>
@@ -43,6 +44,32 @@
 #define P6_EVENT_CPU_CLOCKS_NOT_HALTED	0x79
 #define P6_NMI_EVENT		P6_EVENT_CPU_CLOCKS_NOT_HALTED
 
+#define MSR_P4_MISC_ENABLE	0x1A0
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL	(1<<7)
+#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL	(1<<12)
+#define MSR_P4_PERFCTR0		0x300
+#define MSR_P4_CCCR0		0x360
+#define P4_ESCR_EVENT_SELECT(N)	((N)<<25)
+#define P4_ESCR_OS		(1<<3)
+#define P4_ESCR_USR		(1<<2)
+#define P4_CCCR_OVF_PMI		(1<<26)
+#define P4_CCCR_THRESHOLD(N)	((N)<<20)
+#define P4_CCCR_COMPLEMENT	(1<<19)
+#define P4_CCCR_COMPARE		(1<<18)
+#define P4_CCCR_REQUIRED	(3<<16)
+#define P4_CCCR_ESCR_SELECT(N)	((N)<<13)
+#define P4_CCCR_ENABLE		(1<<12)
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+   CRU_ESCR0 (with any non-null event selector) through a complemented
+   max threshold. [IA32-Vol3, Section 14.9.9] */
+#define MSR_P4_IQ_COUNTER0	0x30C
+#define MSR_P4_IQ_CCCR0		0x36C
+#define MSR_P4_CRU_ESCR0	0x3B8
+#define P4_NMI_CRU_ESCR0	(P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0	\
+	(P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
+	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
 int __init check_nmi_watchdog (void)
 {
 	irq_cpustat_t tmp[NR_CPUS];
@@ -84,11 +111,11 @@
 	/*
 	 * If any other x86 CPU has a local APIC, then
 	 * please test the NMI stuff there and send me the
-	 * missing bits. Right now Intel P6 and AMD K7 only.
+	 * missing bits. Right now Intel P6/P4 and AMD K7 only.
 	 */
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-			(boot_cpu_data.x86 == 6))
+			(boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
 		nmi_watchdog = nmi;
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
@@ -118,7 +145,15 @@
 		wrmsr(MSR_K7_EVNTSEL0, 0, 0);
 		break;
 	case X86_VENDOR_INTEL:
-		wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+		switch (boot_cpu_data.x86) {
+		case 6:
+			wrmsr(MSR_P6_EVNTSEL0, 0, 0);
+			break;
+		case 15:
+			wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+			wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+			break;
+		}
 		break;
 	}
 }
@@ -157,17 +192,22 @@
  * Original code written by Keith Owens.
  */
 
+static void __pminit clear_msr_range(unsigned int base, unsigned int n)
+{
+	unsigned int i;
+
+	for(i = 0; i < n; ++i)
+		wrmsr(base+i, 0, 0);
+}
+
 static void __pminit setup_k7_watchdog(void)
 {
-	int i;
 	unsigned int evntsel;
 
 	nmi_perfctr_msr = MSR_K7_PERFCTR0;
 
-	for(i = 0; i < 4; ++i) {
-		wrmsr(MSR_K7_EVNTSEL0+i, 0, 0);
-		wrmsr(MSR_K7_PERFCTR0+i, 0, 0);
-	}
+	clear_msr_range(MSR_K7_EVNTSEL0, 4);
+	clear_msr_range(MSR_K7_PERFCTR0, 4);
 
 	evntsel = K7_EVNTSEL_INT
 		| K7_EVNTSEL_OS
@@ -184,27 +224,54 @@
 
 static void __pminit setup_p6_watchdog(void)
 {
-	int i;
 	unsigned int evntsel;
 
-	nmi_perfctr_msr = MSR_IA32_PERFCTR0;
+	nmi_perfctr_msr = MSR_P6_PERFCTR0;
 
-	for(i = 0; i < 2; ++i) {
-		wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0);
-		wrmsr(MSR_IA32_PERFCTR0+i, 0, 0);
-	}
+	clear_msr_range(MSR_P6_EVNTSEL0, 2);
+	clear_msr_range(MSR_P6_PERFCTR0, 2);
 
 	evntsel = P6_EVNTSEL_INT
 		| P6_EVNTSEL_OS
 		| P6_EVNTSEL_USR
 		| P6_NMI_EVENT;
 
-	wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
-	Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
-	wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+	Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= P6_EVNTSEL0_ENABLE;
-	wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+}
+
+static int __pminit setup_p4_watchdog(void)
+{
+	unsigned int misc_enable, dummy;
+
+	rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+		return 0;
+
+	nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+		clear_msr_range(0x3F1, 2);
+	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+	   docs doesn't fully define it, so leave it alone for now. */
+	clear_msr_range(0x3A0, 31);
+	clear_msr_range(0x3C0, 6);
+	clear_msr_range(0x3C8, 6);
+	clear_msr_range(0x3E0, 2);
+	clear_msr_range(MSR_P4_CCCR0, 18);
+	clear_msr_range(MSR_P4_PERFCTR0, 18);
+
+	wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+	Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+	return 1;
 }
 
 void __pminit setup_apic_nmi_watchdog (void)
@@ -216,9 +283,17 @@
 		setup_k7_watchdog();
 		break;
 	case X86_VENDOR_INTEL:
-		if (boot_cpu_data.x86 != 6)
+		switch (boot_cpu_data.x86) {
+		case 6:
+			setup_p6_watchdog();
+			break;
+		case 15:
+			if (!setup_p4_watchdog())
+				return;
+			break;
+		default:
 			return;
-		setup_p6_watchdog();
+		}
 		break;
 	default:
 		return;
@@ -283,7 +358,7 @@
 			 * to get a message out.
 			 */
 			bust_spinlocks(1);
-			printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
+			printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
 			show_registers(regs);
 			printk("console shuts up ...\n");
 			console_silent();
@@ -295,6 +370,18 @@
 		last_irq_sums[cpu] = sum;
 		alert_counter[cpu] = 0;
 	}
-	if (nmi_perfctr_msr)
+	if (nmi_perfctr_msr) {
+		if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+			/*
+			 * P4 quirks:
+			 * - An overflown perfctr will assert its interrupt
+			 *   until the OVF flag in its CCCR is cleared.
+			 * - LVTPC is masked on interrupt and must be
+			 *   unmasked by the LVTPC handler.
+			 */
+			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+			apic_write(APIC_LVTPC, APIC_DM_NMI);
+		}
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+	}
 }
diff -urN linux-2.4.19-pre2/arch/i386/kernel/setup.c linux-2.4.19-pre3/arch/i386/kernel/setup.c
--- linux-2.4.19-pre2/arch/i386/kernel/setup.c	Mon Feb 25 11:37:53 2002
+++ linux-2.4.19-pre3/arch/i386/kernel/setup.c	Mon Mar 11 14:13:25 2002
@@ -98,6 +98,8 @@
 #endif
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
 #include <linux/seq_file.h>
 #include <asm/processor.h>
 #include <linux/console.h>
@@ -155,6 +157,7 @@
 unsigned char aux_device_present;
 
 extern void mcheck_init(struct cpuinfo_x86 *c);
+extern void dmi_scan_machine(void);
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
@@ -1042,6 +1045,7 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
+	dmi_scan_machine();
 }
 
 static int cachesize_override __initdata = -1;
@@ -1306,7 +1310,7 @@
 }
 
 /*
- * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
 static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
@@ -1468,11 +1472,6 @@
 		break;
 
 	case 4: /* MediaGX/GXm */
-		/*
-		 *	Life sometimes gets weiiiiiiiird if we use this
-		 *	on the MediaGX. So we turn it off for now. 
-		 */
-		
 #ifdef CONFIG_PCI
 		/* It isnt really a PCI quirk directly, but the cure is the
 		   same. The MediaGX has deep magic SMM stuff that handles the
@@ -1494,14 +1493,22 @@
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
 			get_model_name(c);  /* get CPU marketing name */
-			clear_bit(X86_FEATURE_TSC, c->x86_capability);
+			/*
+	 		 *	The 5510/5520 companion chips have a funky PIT
+			 *	that breaks the TSC synchronizing, so turn it off
+			 */
+			if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+			   pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+				clear_bit(X86_FEATURE_TSC, c->x86_capability);
 			return;
 		}
 		else {  /* MediaGX */
 			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
 			p = Cx86_cb+2;
 			c->x86_model = (dir1 & 0x20) ? 1 : 2;
-			clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+			if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+			   pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+				clear_bit(X86_FEATURE_TSC, &c->x86_capability);
 		}
 		break;
 
@@ -2270,6 +2277,8 @@
 		c->x86_vendor = X86_VENDOR_AMD;
 	else if (!strcmp(v, "CyrixInstead"))
 		c->x86_vendor = X86_VENDOR_CYRIX;
+	else if (!strcmp(v, "Geode by NSC"))
+		c->x86_vendor = X86_VENDOR_NSC;
 	else if (!strcmp(v, "UMC UMC UMC "))
 		c->x86_vendor = X86_VENDOR_UMC;
 	else if (!strcmp(v, "CentaurHauls"))
@@ -2613,6 +2622,10 @@
 		init_cyrix(c);
 		break;
 
+	case X86_VENDOR_NSC:
+	        init_cyrix(c);
+		break;
+
 	case X86_VENDOR_AMD:
 		init_amd(c);
 		break;
@@ -2713,14 +2726,17 @@
 {
 	get_cpu_vendor(&boot_cpu_data);
 
-	if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX )
+	if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ||
+	     boot_cpu_data.x86_vendor == X86_VENDOR_NSC )
 		init_cyrix(&boot_cpu_data);
 }
 
 
 /* These need to match <asm/processor.h> */
 static char *cpu_vendor_names[] __initdata = {
-	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
+	"Intel", "Cyrix", "AMD", "UMC", "NexGen", 
+	"Centaur", "Rise", "Transmeta", "NSC"
+};
 
 
 void __init print_cpu_info(struct cpuinfo_x86 *c)
diff -urN linux-2.4.19-pre2/arch/i386/kernel/signal.c linux-2.4.19-pre3/arch/i386/kernel/signal.c
--- linux-2.4.19-pre2/arch/i386/kernel/signal.c	Mon Feb 25 11:37:53 2002
+++ linux-2.4.19-pre3/arch/i386/kernel/signal.c	Mon Mar 11 14:13:25 2002
@@ -685,10 +685,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/i386/kernel/traps.c linux-2.4.19-pre3/arch/i386/kernel/traps.c
--- linux-2.4.19-pre2/arch/i386/kernel/traps.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre3/arch/i386/kernel/traps.c	Mon Mar 11 14:13:25 2002
@@ -505,6 +505,8 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+		if ((regs->xcs & 3) == 0)
+			goto clear_TF;
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
diff -urN linux-2.4.19-pre2/arch/i386/mm/init.c linux-2.4.19-pre3/arch/i386/mm/init.c
--- linux-2.4.19-pre2/arch/i386/mm/init.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre3/arch/i386/mm/init.c	Mon Mar 11 14:13:25 2002
@@ -128,7 +128,6 @@
 static inline void set_pte_phys (unsigned long vaddr,
 			unsigned long phys, pgprot_t flags)
 {
-	pgprot_t prot;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
@@ -144,10 +143,8 @@
 		return;
 	}
 	pte = pte_offset(pmd, vaddr);
-	if (pte_val(*pte))
-		pte_ERROR(*pte);
-	pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags);
-	set_pte(pte, mk_pte_phys(phys, prot));
+	/* <phys,flags> stored as-is, to permit clearing entries */
+	set_pte(pte, mk_pte_phys(phys, flags));
 
 	/*
 	 * It's enough to flush this one mapping.
@@ -462,8 +459,9 @@
 #ifdef CONFIG_HIGHMEM
 	highmem_start_page = mem_map + highstart_pfn;
 	max_mapnr = num_physpages = highend_pfn;
+	num_mappedpages = max_low_pfn;
 #else
-	max_mapnr = num_physpages = max_low_pfn;
+	max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
 #endif
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
diff -urN linux-2.4.19-pre2/arch/i386/mm/ioremap.c linux-2.4.19-pre3/arch/i386/mm/ioremap.c
--- linux-2.4.19-pre2/arch/i386/mm/ioremap.c	Tue Mar 20 08:13:33 2001
+++ linux-2.4.19-pre3/arch/i386/mm/ioremap.c	Mon Mar 11 14:13:25 2002
@@ -161,3 +161,68 @@
 	if (addr > high_memory)
 		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
+
+void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
+{
+	unsigned long offset, last_addr;
+	unsigned int nrpages;
+	enum fixed_addresses idx;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+	/*
+	 * Don't remap the low PCI/ISA area, it's always mapped..
+	 */
+	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
+		return phys_to_virt(phys_addr);
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Mappings have to fit in the FIX_BTMAP area.
+	 */
+	nrpages = size >> PAGE_SHIFT;
+	if (nrpages > NR_FIX_BTMAPS)
+		return NULL;
+
+	/*
+	 * Ok, go for it..
+	 */
+	idx = FIX_BTMAP_BEGIN;
+	while (nrpages > 0) {
+		set_fixmap(idx, phys_addr);
+		phys_addr += PAGE_SIZE;
+		--idx;
+		--nrpages;
+	}
+	return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN));
+}
+
+void __init bt_iounmap(void *addr, unsigned long size)
+{
+	unsigned long virt_addr;
+	unsigned long offset;
+	unsigned int nrpages;
+	enum fixed_addresses idx;
+
+	virt_addr = (unsigned long)addr;
+	if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN))
+		return;
+	offset = virt_addr & ~PAGE_MASK;
+	nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
+
+	idx = FIX_BTMAP_BEGIN;
+	while (nrpages > 0) {
+		__set_fixmap(idx, 0, __pgprot(0));
+		--idx;
+		--nrpages;
+	}
+}
diff -urN linux-2.4.19-pre2/arch/ia64/kernel/entry.S linux-2.4.19-pre3/arch/ia64/kernel/entry.S
--- linux-2.4.19-pre2/arch/ia64/kernel/entry.S	Mon Mar 11 14:13:10 2002
+++ linux-2.4.19-pre3/arch/ia64/kernel/entry.S	Mon Mar 11 14:13:25 2002
@@ -1145,7 +1145,7 @@
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_tkill
 	data8 ia64_ni_syscall			// 1230
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff -urN linux-2.4.19-pre2/arch/ia64/kernel/signal.c linux-2.4.19-pre3/arch/ia64/kernel/signal.c
--- linux-2.4.19-pre2/arch/ia64/kernel/signal.c	Mon Mar 11 14:13:11 2002
+++ linux-2.4.19-pre3/arch/ia64/kernel/signal.c	Mon Mar 11 14:13:25 2002
@@ -584,10 +584,7 @@
 				/* FALLTHRU */
 
 			      default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/m68k/kernel/entry.S linux-2.4.19-pre3/arch/m68k/kernel/entry.S
--- linux-2.4.19-pre2/arch/m68k/kernel/entry.S	Mon Oct  8 10:39:18 2001
+++ linux-2.4.19-pre3/arch/m68k/kernel/entry.S	Mon Mar 11 14:13:26 2002
@@ -646,6 +646,8 @@
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
+	.long SYMBOL_NAME(sys_gettid)
+	.long SYMBOL_NAME(sys_tkill)
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.4.19-pre2/arch/m68k/kernel/signal.c linux-2.4.19-pre3/arch/m68k/kernel/signal.c
--- linux-2.4.19-pre2/arch/m68k/kernel/signal.c	Wed Jan 24 15:21:28 2001
+++ linux-2.4.19-pre3/arch/m68k/kernel/signal.c	Mon Mar 11 14:13:26 2002
@@ -1135,10 +1135,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/mips/baget/vacserial.c linux-2.4.19-pre3/arch/mips/baget/vacserial.c
--- linux-2.4.19-pre2/arch/mips/baget/vacserial.c	Mon Mar 11 14:13:13 2002
+++ linux-2.4.19-pre3/arch/mips/baget/vacserial.c	Mon Mar 11 14:13:26 2002
@@ -1785,7 +1785,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -urN linux-2.4.19-pre2/arch/mips/kernel/signal.c linux-2.4.19-pre3/arch/mips/kernel/signal.c
--- linux-2.4.19-pre2/arch/mips/kernel/signal.c	Sun Sep  9 10:43:01 2001
+++ linux-2.4.19-pre3/arch/mips/kernel/signal.c	Mon Mar 11 14:13:26 2002
@@ -204,7 +204,7 @@
 #define restore_gp_reg(i) do {						\
 	err |= __get_user(reg, &sc->sc_regs[i]);			\
 	regs->regs[i] = reg;						\
-} while(0);
+} while(0)
 	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
 	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
 	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
@@ -661,10 +661,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/mips/kernel/syscalls.h linux-2.4.19-pre3/arch/mips/kernel/syscalls.h
--- linux-2.4.19-pre2/arch/mips/kernel/syscalls.h	Mon Mar 11 14:13:17 2002
+++ linux-2.4.19-pre3/arch/mips/kernel/syscalls.h	Mon Mar 11 14:13:26 2002
@@ -250,3 +250,5 @@
 SYS(sys_ni_syscall, 0)				/* reserved for removexattr */
 SYS(sys_ni_syscall, 0)				/* reserved for lremovexattr */
 SYS(sys_ni_syscall, 0)				/* 4235 res. for fremovexattr */
+SYS(sys_gettid, 0)
+SYS(sys_tkill, 2)
diff -urN linux-2.4.19-pre2/arch/mips64/kernel/scall_64.S linux-2.4.19-pre3/arch/mips64/kernel/scall_64.S
--- linux-2.4.19-pre2/arch/mips64/kernel/scall_64.S	Mon Mar 11 14:13:19 2002
+++ linux-2.4.19-pre3/arch/mips64/kernel/scall_64.S	Mon Mar 11 14:13:26 2002
@@ -362,3 +362,4 @@
 	PTR	sys_ni_syscall			/* reserved for removexattr */
 	PTR	sys_ni_syscall			/* reserved for lremovexattr */
 	PTR	sys_ni_syscall			/* reserved for fremovexattr */
+	PTR	sys_tkill
diff -urN linux-2.4.19-pre2/arch/mips64/kernel/scall_o32.S linux-2.4.19-pre3/arch/mips64/kernel/scall_o32.S
--- linux-2.4.19-pre2/arch/mips64/kernel/scall_o32.S	Mon Mar 11 14:13:19 2002
+++ linux-2.4.19-pre3/arch/mips64/kernel/scall_o32.S	Mon Mar 11 14:13:26 2002
@@ -482,6 +482,7 @@
 	sys	sys_ni_syscall	0		/* reserved for removexattr */
 	sys	sys_ni_syscall	0		/* reserved for lremovexattr */
 	sys	sys_ni_syscall	0		/* 4235 res. for fremovexattr */
+	sys	sys32_tkill	2
 
 	.endm
 
diff -urN linux-2.4.19-pre2/arch/mips64/kernel/signal.c linux-2.4.19-pre3/arch/mips64/kernel/signal.c
--- linux-2.4.19-pre2/arch/mips64/kernel/signal.c	Sun Sep  9 10:43:01 2001
+++ linux-2.4.19-pre3/arch/mips64/kernel/signal.c	Mon Mar 11 14:13:26 2002
@@ -685,10 +685,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/mips64/kernel/signal32.c linux-2.4.19-pre3/arch/mips64/kernel/signal32.c
--- linux-2.4.19-pre2/arch/mips64/kernel/signal32.c	Mon Mar 11 14:13:19 2002
+++ linux-2.4.19-pre3/arch/mips64/kernel/signal32.c	Mon Mar 11 14:13:26 2002
@@ -757,10 +757,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/mips64/sgi-ip27/ip27-rtc.c linux-2.4.19-pre3/arch/mips64/sgi-ip27/ip27-rtc.c
--- linux-2.4.19-pre2/arch/mips64/sgi-ip27/ip27-rtc.c	Mon Mar 11 14:13:21 2002
+++ linux-2.4.19-pre3/arch/mips64/sgi-ip27/ip27-rtc.c	Mon Mar 11 14:13:26 2002
@@ -222,7 +222,8 @@
 	    KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0;
 
 	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
+	if (misc_register(&rtc_dev))
+		return -ENODEV;
 	create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL);
 
 	save_flags(flags);
diff -urN linux-2.4.19-pre2/arch/parisc/kernel/signal.c linux-2.4.19-pre3/arch/parisc/kernel/signal.c
--- linux-2.4.19-pre2/arch/parisc/kernel/signal.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.19-pre3/arch/parisc/kernel/signal.c	Mon Mar 11 14:13:26 2002
@@ -581,11 +581,7 @@
 				/* FALLTHRU */
 
 			default:
-				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/parisc/kernel/syscall.S linux-2.4.19-pre3/arch/parisc/kernel/syscall.S
--- linux-2.4.19-pre2/arch/parisc/kernel/syscall.S	Mon Oct  8 10:39:18 2001
+++ linux-2.4.19-pre3/arch/parisc/kernel/syscall.S	Mon Mar 11 14:13:26 2002
@@ -552,6 +552,8 @@
 	ENTRY_UHOH(shmctl)		/* 195 */
 	ENTRY_SAME(ni_syscall)		/* streams1 */
 	ENTRY_SAME(ni_syscall)		/* streams2 */
+	ENTRY_SAME(gettid)
+	ENTRY_SAME(tkill)
 
 .end
 
diff -urN linux-2.4.19-pre2/arch/ppc/kernel/misc.S linux-2.4.19-pre3/arch/ppc/kernel/misc.S
--- linux-2.4.19-pre2/arch/ppc/kernel/misc.S	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre3/arch/ppc/kernel/misc.S	Mon Mar 11 14:13:27 2002
@@ -478,9 +478,9 @@
  * snoop from the data cache.
  * This is a no-op on the 601 which has a unified cache.
  *
- *	void __flush_page_to_ram(void *page)
+ *	void __flush_dcache_icache(void *page)
  */
-_GLOBAL(__flush_page_to_ram)
+_GLOBAL(__flush_dcache_icache)
 	mfspr	r5,PVR
 	rlwinm	r5,r5,16,16,31
 	cmpi	0,r5,1
@@ -500,28 +500,6 @@
 	sync
 	isync
 	blr
-
-/*
- * Flush a particular page from the instruction cache.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * This is a no-op on the 601 which has a unified cache.
- *
- *	void __flush_icache_page(void *page)
- */
-_GLOBAL(__flush_icache_page)
-	mfspr	r5,PVR
-	rlwinm	r5,r5,16,16,31
-	cmpi	0,r5,1
-	beqlr					/* for 601, do nothing */
-	li	r4,4096/L1_CACHE_LINE_SIZE	/* Number of lines in a page */
-	mtctr	r4
-1:	icbi	0,r3
-	addi	r3,r3,L1_CACHE_LINE_SIZE
-	bdnz	1b
-	sync
-	isync
-	blr
 	
 /*
  * Clear a page using the dcbz instruction, which doesn't cause any
@@ -1122,6 +1100,7 @@
 	.long sys_madvise	/* 205 */
 	.long sys_mincore
 	.long sys_gettid
+	.long sys_tkill
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
 	.endr
diff -urN linux-2.4.19-pre2/arch/ppc/kernel/ppc_ksyms.c linux-2.4.19-pre3/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.19-pre2/arch/ppc/kernel/ppc_ksyms.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre3/arch/ppc/kernel/ppc_ksyms.c	Mon Mar 11 14:13:27 2002
@@ -189,6 +189,9 @@
 EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_range);
+EXPORT_SYMBOL(flush_icache_user_range);
+EXPORT_SYMBOL(flush_icache_page);
+EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(xchg_u32);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(last_task_used_altivec);
diff -urN linux-2.4.19-pre2/arch/ppc/kernel/setup.c linux-2.4.19-pre3/arch/ppc/kernel/setup.c
--- linux-2.4.19-pre2/arch/ppc/kernel/setup.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/arch/ppc/kernel/setup.c	Mon Mar 11 14:13:27 2002
@@ -694,8 +694,12 @@
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
 	id->word92         = __le16_to_cpu(id->word92);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
-	for (i = 0; i < 32; i++)
-		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
 	id->last_lun       = __le16_to_cpu(id->last_lun);
 	id->word127        = __le16_to_cpu(id->word127);
 	id->dlf            = __le16_to_cpu(id->dlf);
@@ -705,6 +709,12 @@
 	id->word156        = __le16_to_cpu(id->word156);
 	for (i = 0; i < 3; i++)
 		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	for (i = 0; i < 96; i++)
-		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
diff -urN linux-2.4.19-pre2/arch/ppc/kernel/signal.c linux-2.4.19-pre3/arch/ppc/kernel/signal.c
--- linux-2.4.19-pre2/arch/ppc/kernel/signal.c	Mon Nov 26 05:29:17 2001
+++ linux-2.4.19-pre3/arch/ppc/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -645,10 +645,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/ppc/mm/init.c linux-2.4.19-pre3/arch/ppc/mm/init.c
--- linux-2.4.19-pre2/arch/ppc/mm/init.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre3/arch/ppc/mm/init.c	Mon Mar 11 14:13:27 2002
@@ -596,23 +596,43 @@
 	mem_pieces_remove(&phys_avail, start, size, 1);
 }
 
-void flush_page_to_ram(struct page *page)
+/*
+ * This is called when a page has been modified by the kernel.
+ * It just marks the page as not i-cache clean.  We do the i-cache
+ * flush later when the page is given to a user process, if necessary.
+ */
+void flush_dcache_page(struct page *page)
 {
-	unsigned long vaddr = (unsigned long) kmap(page);
-	__flush_page_to_ram(vaddr);
-	kunmap(page);
+	clear_bit(PG_arch_1, &page->flags);
 }
 
-/*
- * set_pte stores a linux PTE into the linux page table.
- * On machines which use an MMU hash table we avoid changing the
- * _PAGE_HASHPTE bit.
- */
-void set_pte(pte_t *ptep, pte_t pte)
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	if (page->mapping && !PageReserved(page)
+	    && !test_bit(PG_arch_1, &page->flags)) {
+		__flush_dcache_icache(kmap(page));
+		kunmap(page);
+		set_bit(PG_arch_1, &page->flags);
+	}
+}
+
+void clear_user_page(void *page, unsigned long vaddr)
 {
-#if _PAGE_HASHPTE != 0
-	pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
-#else
-	*ptep = pte;
-#endif
+	clear_page(page);
+}
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
+{
+	copy_page(vto, vfrom);
+	__flush_dcache_icache(vto);
+}
+
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+			     unsigned long addr, int len)
+{
+	unsigned long maddr;
+
+	maddr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
+	flush_icache_range(maddr, maddr + len);
+	kunmap(page);
 }
diff -urN linux-2.4.19-pre2/arch/s390/Makefile linux-2.4.19-pre3/arch/s390/Makefile
--- linux-2.4.19-pre2/arch/s390/Makefile	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/Makefile	Mon Mar 11 14:13:27 2002
@@ -60,6 +60,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
+	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
 
diff -urN linux-2.4.19-pre2/arch/s390/boot/install.sh linux-2.4.19-pre3/arch/s390/boot/install.sh
--- linux-2.4.19-pre2/arch/s390/boot/install.sh	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/arch/s390/boot/install.sh	Mon Mar 11 14:13:27 2002
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/s390x/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for s390 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+	mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+	mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
diff -urN linux-2.4.19-pre2/arch/s390/config.in linux-2.4.19-pre3/arch/s390/config.in
--- linux-2.4.19-pre2/arch/s390/config.in	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/config.in	Mon Mar 11 14:13:27 2002
@@ -7,8 +7,8 @@
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_UID16 y
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 mainmenu_name "Linux Kernel Configuration"
@@ -37,6 +37,8 @@
 mainmenu_option next_comment
 comment 'General setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
+bool 'Use chscs for Common I/O' CONFIG_CHSC
 bool 'Builtin IPL record support' CONFIG_IPL
 if [ "$CONFIG_IPL" = "y" ]; then
   choice 'IPL method generated into head.S' \
diff -urN linux-2.4.19-pre2/arch/s390/defconfig linux-2.4.19-pre3/arch/s390/defconfig
--- linux-2.4.19-pre2/arch/s390/defconfig	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/defconfig	Mon Mar 11 14:13:27 2002
@@ -5,8 +5,8 @@
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_GENERIC_BUST_SPINLOCK is not set
 CONFIG_ARCH_S390=y
 
@@ -131,8 +131,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -144,10 +142,10 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
-# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -165,7 +163,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
+CONFIG_NET_FASTROUTE=y
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -urN linux-2.4.19-pre2/arch/s390/kernel/Makefile linux-2.4.19-pre3/arch/s390/kernel/Makefile
--- linux-2.4.19-pre2/arch/s390/kernel/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/s390/kernel/Makefile	Mon Mar 11 14:13:27 2002
@@ -10,7 +10,7 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
-all: kernel.o head.o init_task.o
+all: asm-offsets.h kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 
@@ -27,5 +27,29 @@
 #
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-stub.o #gdb-low.o 
 
+.PHONY: asm-offsets.h
+
+entry.S: asm-offsets.h
+
+#
+# Automatic offset generation for assembler files.
+#
+asm-offsets.h: asm-offsets.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \
+	(echo "#ifndef __ASM_OFFSETS_H__"; \
+	 echo "#define __ASM_OFFSETS_H__"; \
+	 echo "/*"; \
+	 echo " * DO NOT MODIFY"; \
+	 echo " *"; \
+	 echo " * This file was generated by arch/s390/kernel/Makefile"; \
+	 echo " */"; \
+	 sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \
+	     -e "s:->::"; \
+	 echo "#endif" \
+	) > asm-offsets.h
+
+clean:
+	rm -f asm-offsets.h
+
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.19-pre2/arch/s390/kernel/asm-offsets.c linux-2.4.19-pre3/arch/s390/kernel/asm-offsets.c
--- linux-2.4.19-pre2/arch/s390/kernel/asm-offsets.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/arch/s390/kernel/asm-offsets.c	Mon Mar 11 14:13:27 2002
@@ -0,0 +1,32 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val, marker) \
+	asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),);
+	DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),);
+	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
+	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+	BLANK();
+	DEFINE(__TASK_state, offsetof(struct task_struct, state),);
+	DEFINE(__TASK_sigpending, offsetof(struct task_struct, sigpending),);
+	DEFINE(__TASK_need_resched,
+	       offsetof(struct task_struct, need_resched),);
+	DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),);
+	DEFINE(__TASK_processor, offsetof(struct task_struct, processor),);
+
+	return 0;
+}
diff -urN linux-2.4.19-pre2/arch/s390/kernel/entry.S linux-2.4.19-pre3/arch/s390/kernel/entry.S
--- linux-2.4.19-pre2/arch/s390/kernel/entry.S	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/entry.S	Mon Mar 11 14:13:27 2002
@@ -18,6 +18,8 @@
 #include <asm/smp.h>
 #include <asm/ptrace.h>
 
+#include "asm-offsets.h"
+
 /*
  * Stack layout for the system_call stack entry.
  * The first few entries are identical to the user_regs_struct.
@@ -44,42 +46,7 @@
 SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
 /* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
-#if CONFIG_REMOTE_DEBUG
-SP_CRREGS    =  (SP_TRAP+4)
-/* fpu registers are saved & restored by the gdb stub itself */
-SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
-SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
-#else
-SP_PGM_OLD_ILC= (SP_TRAP+4)
-#endif
-SP_SIZE      =  (SP_PGM_OLD_ILC+4)
-/*
- * these defines are offsets into the thread_struct
- */
-_TSS_PTREGS  = 0
-_TSS_FPRS    = (_TSS_PTREGS+8)
-_TSS_AR2     = (_TSS_FPRS+136)
-_TSS_AR4     = (_TSS_AR2+4)
-_TSS_KSP     = (_TSS_AR4+4)
-_TSS_USERSEG = (_TSS_KSP+4)
-_TSS_ERROR   = (_TSS_USERSEG+4)
-_TSS_PROT    = (_TSS_ERROR+4)
-_TSS_TRAP    = (_TSS_PROT+4)
-_TSS_MM      = (_TSS_TRAP+4)
-_TSS_PER     = (_TSS_MM+8)
-_TSS_IEEE    = (_TSS_PER+36)
-_TSS_FLAGS   = (_TSS_IEEE+4)
-
-/*
- * these are offsets into the task-struct.
- */
-state        =  0
-flags        =  4
-sigpending   =  8
-need_resched = 24
-tsk_ptrace   = 28
-processor    = 52
+SP_SIZE      =  (SP_TRAP+4)
 
 /*
  * Base Address of this Module --- saved in __LC_ENTRY_BASE
@@ -97,12 +64,15 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL psworg,sync      # system entry macro
+        .macro  SAVE_ALL_BASE
         stm     %r13,%r15,__LC_SAVE_AREA
         basr    %r13,0                    #  temp base pointer
-        l       %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 
+0:	stam    %a2,%a4,__LC_SAVE_AREA+12
+        l       %r13,.Lentry_base-0b(%r13)# load &entry_base to %r13
+	.endm
+
+        .macro  SAVE_ALL psworg,sync      # system entry macro
         tm      \psworg+1,0x01            # test problem state bit
-        stam    %a2,%a4,__LC_SAVE_AREA+12
 	.if	\sync
         bz      BASED(1f)                 # skip stack setup save
 	.else
@@ -146,8 +116,8 @@
 
 /*
  * Scheduler resume function, called by switch_to
- *  grp2 = (thread_struct *) prev->tss
- *  grp3 = (thread_struct *) next->tss
+ *  gpr2 = (task_struct *) prev
+ *  gpr3 = (task_struct *) next
  * Returns:
  *  gpr2 = prev
  */
@@ -155,30 +125,24 @@
 resume:
         basr    %r1,0
 resume_base:
-        l       %r4,_TSS_PTREGS(%r3)
-        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
-        bz      resume_noper-resume_base(%r1) # if not we're fine
-        stctl   %c9,%c11,24(%r15)             # We are using per stuff
-        clc     _TSS_PER(12,%r3),24(%r15)
-        be      resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
-        lctl    %c9,%c11,_TSS_PER(%r3)        # Nope we didn't
+	tm	__THREAD_per(%r3),0xe8		# new process is using per ?
+	bz	resume_noper-resume_base(%r1)	# if not we're fine
+        stctl   %c9,%c11,24(%r15)		# We are using per stuff
+        clc     __THREAD_per(12,%r3),24(%r15)
+        be      resume_noper-resume_base(%r1)	# we got away w/o bashing TLB's
+        lctl    %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 resume_noper:
         stm     %r6,%r15,24(%r15)       # store resume registers of prev task
-        st      %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
-        lr      %r0,%r15
-        n       %r0,.Lc0xffffe000-resume_base(%r1)
-        l       %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
-        l       %r1,.Lc8191-resume_base(%r1)
-        or      %r1,%r15
-        la      %r1,1(%r1)
-        st      %r1,__LC_KERNEL_STACK   # __LC_KERNEL_STACK = new kernel stack
-        stam    %a2,%a2,_TSS_AR2(%r2)   # store kernel access reg. 2
-        stam    %a4,%a4,_TSS_AR4(%r2)   # store kernel access reg. 4
-        lam     %a2,%a2,_TSS_AR2(%r3)   # load kernel access reg. 2
-        lam     %a4,%a4,_TSS_AR4(%r3)   # load kernel access reg. 4
-        lr      %r2,%r0                 # return task_struct of last task
-        lm      %r6,%r15,24(%r15)       # load resume registers of next task
-        br      %r14
+	st	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
+	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
+	stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
+	stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
+	lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
+	lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
+	lm	%r6,%r15,24(%r15)	# load resume registers of next task
+	ahi	%r3,8192
+	st	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
+	br	%r14
 
 /*
  * do_softirq calling function. We want to run the softirq functions on the
@@ -209,16 +173,14 @@
 
 	.globl  system_call
 system_call:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
-pgm_system_call:	
+	lh	%r8,0x8a	  # get svc number from lowcore
+        sll     %r8,2
         GET_CURRENT               # load pointer to task_struct to R9
-        slr     %r8,%r8           # gpr 8 is call save (-> tracesys)
-        ic      %r8,0x8B          # get svc number from lowcore
         stosm   24(%r15),0x03     # reenable interrupts
-        sll     %r8,2
-        l       %r8,sys_call_table-entry_base(8,%r13) # get address of system call
-        tm      tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
+        l       %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr.
+        tm      __TASK_ptrace+3(%r9),0x02 # PT_TRACESYS
         bnz     BASED(sysc_tracesys)
         basr    %r14,%r8          # call sys_xxxx
         st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
@@ -231,14 +193,12 @@
 #
 # check, if reschedule is needed
 #
-        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+        icm     %r0,15,__TASK_need_resched(%r9)
         bnz     BASED(sysc_reschedule)
-        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+        icm     %r0,15,__TASK_sigpending(%r9)
         bnz     BASED(sysc_signal_return)
 sysc_leave:
-	tm      SP_PGM_OLD_ILC(%r15),0xff
-        bz      BASED(pgm_svcret)
-	stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
+	stnsm   24(%r15),0xfc     # disable I/O and ext. interrupts
         RESTORE_ALL 1
 
 #
@@ -250,39 +210,42 @@
         l       %r1,BASED(.Ldo_signal)
 	la      %r14,BASED(sysc_leave)
         br      %r1               # return point is sysc_leave
-
+#
+# call schedule with sysc_return as return-address
+#
+sysc_reschedule:        
+        l       %r1,BASED(.Lschedule)
+	la      %r14,BASED(sysc_return)
+        br      %r1               # call scheduler, return to sysc_return
 #
 # call trace before and after sys_call
 #
 sysc_tracesys:
+	la	%r12,BASED(sysc_return)
+
+#
+# call syscall_trace before and after system call
+# special linkage: %r12 contains the return address for trace_svc
+#
+trace_svc:
         l       %r1,BASED(.Ltrace)
 	l       %r7,BASED(.Lc_ENOSYS)
 	st      %r7,SP_R2(%r15)   # give sysc_trace an -ENOSYS retval
         basr    %r14,%r1
 	l       %r2,SP_R2(%r15)
-	cr      %r2,%r7 # compare with saved -ENOSYS
-	be      BASED(sysc_tracesys_dn1)
-	# strace wants to change the syscall
+	cr      %r2,%r7		  # compare with saved -ENOSYS
+	be      BASED(trace_svc_go) # strace changed the syscall ?
 	sll     %r2,24
 	srl     %r2,22
-        l       %r8,sys_call_table-entry_base(2,%r13) # get address of system call    
-sysc_tracesys_dn1:		
+        l       %r8,sys_call_table-entry_base(%r2,%r13) # get system call addr.
+trace_svc_go:
 	lm      %r3,%r6,SP_R3(%r15)
 	l       %r2,SP_ORIG_R2(%r15)
         basr    %r14,%r8          # call sys_xxx
         st      %r2,SP_R2(%r15)   # store return value
         l       %r1,BASED(.Ltrace)
-	la      %r14,BASED(sysc_return)
-        br      %r1               # return point is sysc_return
-
-
-#
-# call schedule with sysc_return as return-address
-#
-sysc_reschedule:        
-        l       %r1,BASED(.Lschedule)
-	la      %r14,BASED(sysc_return)
-        br      %r1               # call scheduler, return to sysc_return
+	lr	%r14,%r12	  # return point is in %r12
+        br      %r1
 
 #
 # a new process exits the kernel with ret_from_fork
@@ -295,13 +258,9 @@
         stosm   24(%r15),0x03     # reenable interrupts
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-#ifdef CONFIG_SMP
         l       %r1,BASED(.Lschedtail)
 	la      %r14,BASED(sysc_return)
         br      %r1               # call schedule_tail, return to sysc_return
-#else
-        b       BASED(sysc_return)
-#endif
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
@@ -597,11 +556,24 @@
         .long  sys_madvise
 	.long  sys_getdents64		 /* 220 */
         .long  sys_fcntl64 
-	.long  sys_ni_syscall		 /* 222 - reserved for posix_acl */
-	.long  sys_ni_syscall		 /* 223 - reserved for posix_acl */
-	.long  sys_ni_syscall		 /* 224 - reserved for posix_acl */
-	.rept  255-224
+	.long  sys_ni_syscall		 /* 222 - reserved for gettid */
+	.long  sys_ni_syscall		 /* 223 - reserved for tkill */
+	.long  sys_ni_syscall		 /* 224 - reserved for setxattr  */
+	.long  sys_ni_syscall            /* 225 - reserved for lsetxattr */
+	.long  sys_ni_syscall		 /* 226 - reserved for fsetxattr */
+	.long  sys_ni_syscall		 /* 227 - reserved for getxattr  */
+	.long  sys_ni_syscall		 /* 228 - reserved for lgetxattr */
+	.long  sys_ni_syscall		 /* 229 - reserved for fgetxattr */
+	.long  sys_ni_syscall		 /* 230 - reserved for listxattr */
+	.long  sys_ni_syscall		 /* 231 - reserved for llistxattr */
+	.long  sys_ni_syscall		 /* 232 - reserved for flistxattr */
+	.long  sys_ni_syscall		 /* 233 - reserved for removexattr */
+	.long  sys_ni_syscall		 /* 234 - reserved for lremovexattr */
+	.long  sys_ni_syscall		 /* 235 - reserved for fremovexattr */
+	.rept  255-235
 	.long  sys_ni_syscall
+	.long  sys_gettid		/* 226 */
+	.long  sys_tkill		/* 227 */
 	.endr
 
 /*
@@ -623,93 +595,91 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	stm     %r13,%r15,__LC_SAVE_AREA
-	basr    %r13,0                   # temp base pointer
-	l       %r13,.Lentry_base-.(%r13)# load &entry_base to %r13
+	SAVE_ALL_BASE
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
-	stam    %a2,%a4,__LC_SAVE_AREA+12
-        bz      BASED(pgm_sv)            # skip if not
+        bnz     BASED(pgm_per)           # got per exception -> special case
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+        l       %r7,BASED(.Ljump_table)
+        lh      %r8,__LC_PGM_INT_CODE
+        sll     %r8,2
+	GET_CURRENT
+        l       %r7,0(%r8,%r7)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+        l       %r3,__LC_PGM_ILC         # load program interruption code
+	la      %r14,BASED(sysc_return)
+	br      %r7			 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
-        bnz     BASED(pgm_sv)            # skip if it is
+        bnz     BASED(pgm_per_std)       # ok, normal per event from user space
 # ok its one of the special cases, now we need to find out which one
         clc     __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
         be      BASED(pgm_svcper)
 # no interesting special case, ignore PER event
         lm      %r13,%r15,__LC_SAVE_AREA
 	lpsw    0x28
-# it was a single stepped SVC that is causing all the trouble
-pgm_svcper:
-        tm      0x21,0x01                # test problem state bit
-	bz	BASED(.+12)              # skip stack & access regs setup
-	l	%r15,__LC_KERNEL_STACK   # problem state -> load ksp
-	lam     %a2,%a4,BASED(.Lc_ac)    # set ac.reg. 2 to primary space
-                                         # and access reg. 4 to home space
-	s       %r15,BASED(.Lc_spsize)   # make room for registers & psw
-        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
-        stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
-        st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
-        mvc     SP_PSW(8,%r15),0x20      # move user PSW to stack
-        la      %r0,0x20                 # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(4,%r15),0(%r15)        # clear back chain
-        mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
-        b       BASED(pgm_system_call)   # now do the svc
-pgm_svcret:
-        mvi     SP_TRAP+3(%r15),0x28     # set trap indication back to pgm_chk
-        lh      %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-	b       BASED(pgm_no_sv)
-pgm_sv:
-        tm      0x29,0x01                # test problem state bit
-	bz	BASED(.+12)              # skip stack & access regs setup
-	l	%r15,__LC_KERNEL_STACK   # problem state -> load ksp
-	lam     %a2,%a4,BASED(.Lc_ac)    # set ac.reg. 2 to primary space
-                                         # and access reg. 4 to home space
-	s       %r15,BASED(.Lc_spsize)   # make room for registers & psw
-        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
-        stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
-        st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
-        mvc     SP_PSW(8,%r15),0x28      # move user PSW to stack
-        la      %r0,0x28                 # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(4,%r15),0(%r15)        # clear back chain
-	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-        lh      %r7,__LC_PGM_ILC         # load instruction length
+
+#
+# Normal per exception
+#
+pgm_per_std:
+	SAVE_ALL __LC_PGM_OLD_PSW,1
 	GET_CURRENT
-pgm_no_sv:
-	la	%r3,0x7f
-        lh      %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-	nr      %r3,%r8           # reload & clear per-event-bit
-        be      BASED(pgm_dn)     # none of Martins exceptions occurred bypass
+	la	%r4,0x7f
+	l	%r3,__LC_PGM_ILC	 # load program interruption code
+        nr      %r4,%r3                  # clear per-event-bit and ilc
+        be      BASED(pgm_per_only)      # only per or per+check ?
         l       %r1,BASED(.Ljump_table)
-        sll     %r3,2
-        l       %r1,0(%r3,%r1)    # load address of handler routine
-        la      %r2,SP_PTREGS(%r15) # address of register-save area
-        srl     %r3,2
-        cl      %r3,BASED(.Lc4)   # protection-exception ?
-        bne     BASED(pgm_per)    # if not,
-        l       %r5,SP_PSW+4(15)  # load psw addr
-        sr      %r5,%r7           # substract ilc from psw
-        st      %r5,SP_PSW+4(15)  # store corrected psw addr
-pgm_per:basr    %r14,%r1          # branch to interrupt-handler
-pgm_dn: n	%r8,BASED(.Lc128) # check for per excepton
-        be      BASED(pgm_return)
-        la      %r2,SP_PTREGS(15) # address of register-save area
-        l       %r1,BASED(.Lhandle_per) # load adr. of per handler
-        la      %r14,BASED(sysc_return) # load adr. of system return
-        br      %r1               # branch to handle_per_exception
+        sll     %r4,2
+        l       %r1,0(%r4,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+	basr    %r14,%r1		 # branch to interrupt-handler
+pgm_per_only:
+	la      %r2,SP_PTREGS(15)	 # address of register-save area
+        l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
+        la      %r14,BASED(sysc_return)  # load adr. of system return
+        br      %r1			 # branch to handle_per_exception
 
 #
-# the backend code is the same as for sys-call
+# it was a single stepped SVC that is causing all the trouble
 #
-pgm_return:
-        b       BASED(sysc_return)
+pgm_svcper:
+	SAVE_ALL __LC_SVC_OLD_PSW,1
+        GET_CURRENT               # load pointer to task_struct to R9
+	lh	%r8,0x8a	  # get svc number from lowcore
+        sll     %r8,2
+        stosm   24(%r15),0x03     # reenable interrupts
+        l       %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr.
+        tm      __TASK_ptrace+3(%r9),0x02 # PT_TRACESYS
+        bnz     BASED(pgm_tracesys)
+        basr    %r14,%r8          # call sys_xxxx
+        st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
+                                  # ATTENTION: check sys_execve_glue before
+                                  # changing anything here !!
+
+pgm_svcret:
+        icm     %r0,15,__TASK_sigpending(%r9)
+        bz      BASED(pgm_svcper_nosig)
+	la	%r2,SP_PTREGS(%r15) # load pt_regs
+	sr	%r3,%r3		  # clear *oldset
+	l	%r1,BASED(.Ldo_signal)
+	basr	%r4,%r1		  # call do_signal
+	
+pgm_svcper_nosig:
+        mvi     SP_TRAP+3(%r15),0x28     # set trap indication to pgm check
+	la      %r2,SP_PTREGS(15)        # address of register-save area
+        l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
+        la      %r14,BASED(sysc_return)  # load adr. of system return
+        br      %r1                      # branch to handle_per_exception
+#
+# call trace before and after sys_call
+#
+pgm_tracesys:
+	la	%r12,BASED(pgm_svcret)
+	b	BASED(trace_svc)
 
 /*
  * IO interrupt handler routine
@@ -717,21 +687,22 @@
 
         .globl io_int_handler
 io_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_IO_OLD_PSW,0
         GET_CURRENT               # load pointer to task_struct to R9
+        l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         sr      %r3,%r3
-        icm     %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
+        icm     %r3,3,__LC_SUBCHANNEL_NR   # load subchannel nr & extend to int
         l       %r4,__LC_IO_INT_PARM       # load interuption parm
 	l       %r5,__LC_IO_INT_WORD       # load interuption word
-        l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         basr    %r14,%r1          # branch to standard irq handler
 
 io_return:
 #
 # check, if bottom-half has to be done
 #
-        l       %r1,processor(%r9)    # get cpu number from task struture
+        l       %r1,__TASK_processor(%r9)
         sll     %r1,L1_CACHE_SHIFT
         al      %r1,BASED(.Lirq_stat) # get address of irq_stat
         icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
@@ -744,9 +715,9 @@
 #
 # check, if reschedule is needed
 #
-        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+        icm     %r0,15,__TASK_need_resched(%r9)
         bnz     BASED(io_reschedule)
-        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+        icm     %r0,15,__TASK_sigpending(%r9)
         bnz     BASED(io_signal_return)
 io_leave:
         stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
@@ -784,6 +755,7 @@
 
         .globl  ext_int_handler
 ext_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
@@ -812,6 +784,7 @@
 
         .globl mcck_int_handler
 mcck_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_MCK_OLD_PSW,0
 	l       %r1,BASED(.Ls390_mcck)
 	basr    %r14,%r1	  # call machine check handler
@@ -894,7 +867,5 @@
 .Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
 
-#ifdef CONFIG_SMP
 .Lschedtail:   .long  schedule_tail
-#endif
 
diff -urN linux-2.4.19-pre2/arch/s390/kernel/irq.c linux-2.4.19-pre3/arch/s390/kernel/irq.c
--- linux-2.4.19-pre2/arch/s390/kernel/irq.c	Wed Jul 25 14:12:01 2001
+++ linux-2.4.19-pre3/arch/s390/kernel/irq.c	Mon Mar 11 14:13:27 2002
@@ -59,60 +59,6 @@
 BUILD_SMP_INTERRUPT(spurious_interrupt)
 #endif
 
-#if 0
-int get_irq_list(char *buf)
-{
-	int i, j;
-	struct irqaction * action;
-	char *p = buf;
-
-	p += sprintf(p, "           ");
-
-	for (j=0; j<smp_num_cpus; j++)
-		p += sprintf(p, "CPU%d       ",j);
-
-	*p++ = '\n';
-
-	for (i = 0 ; i < NR_IRQS ; i++)
-	{
-		if (ioinfo[i] == INVALID_STORAGE_AREA)
-			continue;
-
-		action = ioinfo[i]->irq_desc.action;
-		
-  		if (!action)
-			continue;
-
-		p += sprintf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-		p += sprintf(p, "%10u ", kstat_irqs(i));
-#else
-		for (j=0; j<smp_num_cpus; j++)
-			p += sprintf( p, "%10u ",
-			              kstat.irqs[cpu_logical_map(j)][i]);
-#endif
-		p += sprintf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
-		p += sprintf(p, "  %s", action->name);
-
-		for (action=action->next; action; action = action->next)
-		{
-			p += sprintf(p, ", %s", action->name);
-
-		} /* endfor */
-
-		*p++ = '\n';
-	
-	} /* endfor */
-
-	p += sprintf(p, "NMI: %10u\n", nmi_counter);
-#ifdef CONFIG_SMP
-	p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
-#endif
-
-	return p - buf;
-}
-#endif
-
 /*
  * Global interrupt locks for SMP. Allow interrupts to come in on any
  * CPU, yet make cli/sti act globally to protect critical regions..
diff -urN linux-2.4.19-pre2/arch/s390/kernel/process.c linux-2.4.19-pre3/arch/s390/kernel/process.c
--- linux-2.4.19-pre2/arch/s390/kernel/process.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/process.c	Mon Mar 11 14:13:27 2002
@@ -50,28 +50,40 @@
  * The idle loop on a S390...
  */
 
-static psw_t wait_psw;
-
 int cpu_idle(void *unused)
 {
+	psw_t wait_psw;
+	unsigned long reg;
+
 	/* endless idle loop with no priority at all */
         init_idle();
 	current->nice = 20;
 	current->counter = -100;
-	wait_psw.mask = _WAIT_PSW_MASK;
-	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
-	while(1) {
-                if (current->need_resched) {
-                        schedule();
-                        check_pgt_cache();
-                        continue;
-                }
-
-		/* load wait psw */
+	while (1) {
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+			continue;
+		}
+
+		/* 
+		 * Wait for external, I/O or machine check interrupt and
+		 * switch of machine check bit after the wait has ended.
+		 */
+		wait_psw.mask = _WAIT_PSW_MASK;
 		asm volatile (
-                        "lpsw %0"
-                        : : "m" (wait_psw) );
-idle_wakeup:
+			"    basr %0,0\n"
+			"0:  la   %0,1f-0b(%0)\n"
+			"    st   %0,4(%1)\n"
+			"    oi   4(%1),0x80\n"
+			"    lpsw 0(%1)\n"
+			"1:  la   %0,2f-1b(%0)\n"
+			"    st   %0,4(%1)\n"
+			"    oi   4(%1),0x80\n"
+			"    ni   1(%1),0xf9\n"
+			"    lpsw 0(%1)\n"
+			"2:"
+			: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
 	}
 }
 
@@ -166,11 +178,9 @@
 
         /* fake return stack for resume(), don't go back to schedule */
         frame->gprs[9]  = (unsigned long) frame;
-	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
-        p->thread.fs = USER_DS;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -urN linux-2.4.19-pre2/arch/s390/kernel/reipl.S linux-2.4.19-pre3/arch/s390/kernel/reipl.S
--- linux-2.4.19-pre2/arch/s390/kernel/reipl.S	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/arch/s390/kernel/reipl.S	Mon Mar 11 14:13:27 2002
@@ -21,8 +21,10 @@
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
         	msch    .Lschib-.Lpg0(%r13) 
-		ssch	.Liplorb-.Lpg0(%r13)           
-		jz	.L001   
+                lhi     %r0,5
+.Lssch:		ssch	.Liplorb-.Lpg0(%r13)           
+		jz	.L001
+                brct    %r0,.Lssch  
 		bas	%r14,.Ldisab-.Lpg0(%r13)
 .L001:		mvc	__LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpsw	.Lwaitpsw-.Lpg0(%r13)          
diff -urN linux-2.4.19-pre2/arch/s390/kernel/s390_ksyms.c linux-2.4.19-pre3/arch/s390/kernel/s390_ksyms.c
--- linux-2.4.19-pre2/arch/s390/kernel/s390_ksyms.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/s390_ksyms.c	Mon Mar 11 14:13:27 2002
@@ -5,6 +5,7 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/smp.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/setup.h>
diff -urN linux-2.4.19-pre2/arch/s390/kernel/setup.c linux-2.4.19-pre3/arch/s390/kernel/setup.c
--- linux-2.4.19-pre2/arch/s390/kernel/setup.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/setup.c	Mon Mar 11 14:13:27 2002
@@ -48,7 +48,7 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
-struct { unsigned long addr, size, type; } memory_chunk[16];
+struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
 #define CHUNK_READ_WRITE 0
 #define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
@@ -284,8 +284,8 @@
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
-	       "We are running under VM\n" :
-	       "We are running native\n");
+	       "We are running under VM (31 bit mode)\n" :
+	       "We are running native (31 bit mode)\n");
 	printk((MACHINE_HAS_IEEE) ?
 	       "This machine has an IEEE fpu\n" :
 	       "This machine has no IEEE fpu\n");
@@ -494,9 +494,9 @@
 			       "bogomips per cpu: %lu.%02lu\n",
 			       smp_num_cpus, loops_per_jiffy/(500000/HZ),
 			       (loops_per_jiffy/(5000/HZ))%100);
-	} 
+	}
 	if (cpu_online_map & (1 << n)) {
-		cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
+		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
 		seq_printf(m, "processor %i: "
 			       "version = %02X,  "
 			       "identification = %06X,  "
diff -urN linux-2.4.19-pre2/arch/s390/kernel/signal.c linux-2.4.19-pre3/arch/s390/kernel/signal.c
--- linux-2.4.19-pre2/arch/s390/kernel/signal.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/s390/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -563,10 +563,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/s390/kernel/smp.c linux-2.4.19-pre3/arch/s390/kernel/smp.c
--- linux-2.4.19-pre2/arch/s390/kernel/smp.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/smp.c	Mon Mar 11 14:13:27 2002
@@ -191,7 +191,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_restart);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_restart();
 }
@@ -208,7 +209,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_halt);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_halt();
 }
@@ -225,7 +227,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_power_off);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_power_off();
 }
@@ -267,7 +270,7 @@
  */
 static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
 {
-        struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+        struct _lowcore *lowcore = get_cpu_lowcore(cpu);
         sigp_ccode ccode;
 
         /*
@@ -291,12 +294,13 @@
         for (i = 0; i < smp_num_cpus; i++) {
                 if (smp_processor_id() == i)
                         continue;
-                lowcore = &get_cpu_lowcore(i);
+                lowcore = get_cpu_lowcore(i);
                 /*
                  * Set signaling bit in lowcore of target cpu and kick it
                  */
                 atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
-                ccode = signal_processor(i, sigp_external_call);
+                while (signal_processor(i, sigp_external_call) == sigp_busy)
+			udelay(10);
         }
 }
 
@@ -313,7 +317,7 @@
 
         /* write magic number to zero page (absolute 0) */
 
-        get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
 
         /* stop all processors */
 
@@ -335,7 +339,7 @@
         for (i =  0; i < smp_num_cpus; i++) {
                 if (smp_processor_id() != i) {
                         int ccode;
-                        low_core_addr = (unsigned long)&get_cpu_lowcore(i);
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
                         do {
                                 ccode = signal_processor_ps(
                                    &dummy,
@@ -479,7 +483,7 @@
         /* Setup the cpu */
         cpu_init();
         /* Print info about this processor */
-        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data);
         /* Wait for completion of smp startup */
         while (!atomic_read(&smp_commenced))
                 /* nothing */ ;
@@ -535,7 +539,7 @@
         unhash_process(idle);
         init_tasks[cpu] = idle;
 
-        cpu_lowcore=&get_cpu_lowcore(cpu);
+        cpu_lowcore = get_cpu_lowcore(cpu);
 	cpu_lowcore->save_area[15] = idle->thread.ksp;
 	cpu_lowcore->kernel_stack = (__u32) idle + 8192;
         __asm__ __volatile__("la    1,%0\n\t"
@@ -589,7 +593,7 @@
         /*
          *      Initialize the logical to physical CPU number mapping
          */
-        print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data);
 
         for(i = 0; i < smp_num_cpus; i++)
         {
@@ -642,3 +646,4 @@
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
diff -urN linux-2.4.19-pre2/arch/s390/kernel/time.c linux-2.4.19-pre3/arch/s390/kernel/time.c
--- linux-2.4.19-pre2/arch/s390/kernel/time.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/time.c	Mon Mar 11 14:13:27 2002
@@ -82,7 +82,7 @@
 {
 	__u64 now;
 
-	asm ("STCK %0" : "=m" (now));
+	asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
         now = (now - init_timer_cc) >> 12;
 	/* We require the offset from the latest update of xtime */
 	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
@@ -200,9 +200,10 @@
 	int cc;
 
         /* kick the TOD clock */
-        asm volatile ("STCK %1\n\t"
+        asm volatile ("STCK 0(%1)\n\t"
                       "IPM  %0\n\t"
-                      "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
+                      "SRL  %0,28" : "=r" (cc) : "a" (&init_timer_cc) 
+				   : "memory", "cc");
         switch (cc) {
         case 0: /* clock in set state: all is fine */
                 break;
diff -urN linux-2.4.19-pre2/arch/s390/kernel/traps.c linux-2.4.19-pre3/arch/s390/kernel/traps.c
--- linux-2.4.19-pre2/arch/s390/kernel/traps.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390/kernel/traps.c	Mon Mar 11 14:13:27 2002
@@ -50,7 +50,9 @@
 #endif
 #endif
 
-extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_segment_exception;
+extern pgm_check_handler_t do_page_exception;
 extern pgm_check_handler_t do_pseudo_page_fault;
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
@@ -269,23 +271,6 @@
         do_exit(SIGSEGV);
 }
 
-#define DO_ERROR(signr, str, name) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-	do_trap(interruption_code, signr, str, regs, NULL); \
-}
-
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-        siginfo_t info; \
-        info.si_signo = signr; \
-        info.si_errno = 0; \
-        info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
-}
-
 static void inline do_trap(long interruption_code, int signr, char *str,
                            struct pt_regs *regs, siginfo_t *info)
 {
@@ -299,7 +284,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code;
+                tsk->thread.trap_no = interruption_code & 0xffff;
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -326,6 +311,11 @@
         }
 }
 
+static inline void *get_check_address(struct pt_regs *regs)
+{
+	return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+}
+
 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
 	if(regs->psw.mask&PSW_PROBLEM_STATE)
@@ -349,14 +339,68 @@
 	return 0;
 }
 
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+        siginfo_t info; \
+        info.si_signo = signr; \
+        info.si_errno = 0; \
+        info.si_code = sicode; \
+        info.si_addr = (void *)siaddr; \
+        do_trap(interruption_code, signr, str, regs, &info); \
+}
+
 DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
-DO_ERROR(SIGILL,  "privileged operation", privileged_op)
-DO_ERROR(SIGILL,  "execute exception", execute_exception)
-DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
-DO_ERROR(SIGILL,  "translation exception", translation_exception)
-DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
-DO_ERROR(SIGILL,  "operand exception", operand_exception)
+
+DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
+	      BUS_ADRERR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
+	      FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
+	      ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void *location,
+           int fpc, long interruption_code)
+{
+	siginfo_t si;
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_addr = location;
+	si.si_code = 0;
+	/* FPC[2] is Data Exception Code */
+	if ((fpc & 0x00000300) == 0) {
+		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
+		if (fpc & 0x8000) /* invalid fp operation */
+			si.si_code = FPE_FLTINV;
+		else if (fpc & 0x4000) /* div by 0 */
+			si.si_code = FPE_FLTDIV;
+		else if (fpc & 0x2000) /* overflow */
+			si.si_code = FPE_FLTOVF;
+		else if (fpc & 0x1000) /* underflow */
+			si.si_code = FPE_FLTUND;
+		else if (fpc & 0x0800) /* inexact */
+			si.si_code = FPE_FLTRES;
+	}
+	current->thread.ieee_instruction_pointer = (addr_t) location;
+	do_trap(interruption_code, SIGFPE,
+		"floating point exception", regs, &si);
+}
 
 asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
@@ -407,11 +451,10 @@
 #endif 
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal)
 		do_trap(interruption_code, signal,
 			"illegal operation", regs, NULL);
 }
@@ -426,7 +469,7 @@
 	__u16 *location = NULL;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -466,16 +509,22 @@
                 }
         } else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
-                do_trap(interruption_code, signal,
-			"specification exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"specification exception", regs, &info);
+	}
 }
 #else
-DO_ERROR(SIGILL, "specification exception", specification_exception)
+DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
+	      ILL_ILLOPN, get_check_address(regs));
 #endif
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
@@ -484,7 +533,7 @@
 	__u16 *location;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -555,13 +604,18 @@
 		signal = SIGFPE;
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-	} else if (signal) 
-                do_trap(interruption_code, signal,
-			"data exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"data exception", regs, &info);
+	}
 }
 
 
@@ -577,13 +631,13 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
-        pgm_check_table[4] = &do_page_fault;
+        pgm_check_table[4] = &do_protection_exception;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
         pgm_check_table[9] = &divide_exception;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
+        pgm_check_table[0x10] = &do_segment_exception;
+        pgm_check_table[0x11] = &do_page_exception;
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
  	pgm_check_table[0x14] = &do_pseudo_page_fault;
diff -urN linux-2.4.19-pre2/arch/s390/mm/fault.c linux-2.4.19-pre3/arch/s390/mm/fault.c
--- linux-2.4.19-pre2/arch/s390/mm/fault.c	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre3/arch/s390/mm/fault.c	Mon Mar 11 14:13:27 2002
@@ -36,7 +36,6 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
-static void force_sigsegv(struct task_struct *tsk, int code, void *address);
 
 extern spinlock_t timerlist_lock;
 
@@ -66,25 +65,95 @@
 }
 
 /*
+ * Check which address space is addressed by the access
+ * register in S390_lowcore.exc_access_id.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static int __check_access_register(struct pt_regs *regs, int error_code)
+{
+	int areg = S390_lowcore.exc_access_id;
+
+	if (areg == 0)
+		/* Access via access register 0 -> kernel address */
+		return 0;
+	if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1)
+		/*
+		 * access register contains 0 -> kernel address,
+		 * access register contains 1 -> user space address
+		 */
+		return regs->acrs[areg];
+
+	/* Something unhealthy was done with the access registers... */
+	die("page fault via unknown access register", regs, error_code);
+	do_exit(SIGKILL);
+	return 0;
+}
+
+/*
+ * Check which address space the address belongs to.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static inline int check_user_space(struct pt_regs *regs, int error_code)
+{
+	/*
+	 * The lowest two bits of S390_lowcore.trans_exc_code indicate
+	 * which paging table was used:
+	 *   0: Primary Segment Table Descriptor
+	 *   1: STD determined via access register
+	 *   2: Secondary Segment Table Descriptor
+	 *   3: Home Segment Table Descriptor
+	 */
+	int descriptor = S390_lowcore.trans_exc_code & 3;
+	if (descriptor == 1)
+		return __check_access_register(regs, error_code);
+	return descriptor >> 1;
+}
+
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
+			  int si_code, unsigned long address)
+{
+	struct siginfo si;
+
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+#if defined(CONFIG_SYSCTL)
+	if (sysctl_userprocess_debug)
+#endif
+	{
+		printk("User process fault: interruption code 0x%lX\n",
+		       error_code);
+		printk("failing address: %lX\n", address);
+		show_regs(regs);
+	}
+#endif
+	si.si_signo = SIGSEGV;
+	si.si_code = si_code;
+	si.si_addr = (void *) address;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+/*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  *
  * error_code:
- *             ****0004       Protection           ->  Write-Protection  (suprression)
- *             ****0010       Segment translation  ->  Not present       (nullification)
- *             ****0011       Page translation     ->  Not present       (nullification)
+ *   04       Protection           ->  Write-Protection  (suprression)
+ *   10       Segment translation  ->  Not present       (nullification)
+ *   11       Page translation     ->  Not present       (nullification)
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
 {
         struct task_struct *tsk;
         struct mm_struct *mm;
         struct vm_area_struct * vma;
         unsigned long address;
+	int user_address;
         unsigned long fixup;
-        int write;
 	int si_code = SEGV_MAPERR;
-	int kernel_address = 0;
 
         tsk = current;
         mm = tsk->mm;
@@ -94,13 +163,13 @@
 	 * as a special case because the translation exception code 
 	 * field is not guaranteed to contain valid data in this case.
 	 */
-	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+	if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) {
 
 		/* Low-address protection hit in kernel mode means 
 		   NULL pointer write access in kernel mode.  */
  		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
 			address = 0;
-			kernel_address = 1;
+			user_address = 0;
 			goto no_context;
 		}
 
@@ -114,52 +183,15 @@
          * more specific the segment and page table portion of 
          * the address 
          */
-
         address = S390_lowcore.trans_exc_code&0x7ffff000;
-
+	user_address = check_user_space(regs, error_code);
 
 	/*
-	 * Check which address space the address belongs to
+	 * Verify that the fault happened in user space, that
+	 * we are not in an interrupt and that there is a 
+	 * user context.
 	 */
-	switch (S390_lowcore.trans_exc_code & 3)
-	{
-	case 0: /* Primary Segment Table Descriptor */
-		kernel_address = 1;
-		goto no_context;
-
-	case 1: /* STD determined via access register */
-		if (S390_lowcore.exc_access_id == 0)
-		{
-			kernel_address = 1;
-			goto no_context;
-		}
-		if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
-		{
-			if (regs->acrs[S390_lowcore.exc_access_id] == 0)
-			{
-				kernel_address = 1;
-				goto no_context;
-			}
-			if (regs->acrs[S390_lowcore.exc_access_id] == 1)
-			{
-				/* user space address */
-				break;
-			}
-		}
-		die("page fault via unknown access register", regs, error_code);
-        	do_exit(SIGKILL);
-		break;
-
-	case 2: /* Secondary Segment Table Descriptor */
-	case 3: /* Home Segment Table Descriptor */
-		/* user space address */
-		break;
-	}
-
-	/*
-	 * Check whether we have a user MM in the first place.
-	 */
-        if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT))
+        if (user_address == 0 || in_interrupt() || !mm)
                 goto no_context;
 
 	/*
@@ -167,7 +199,6 @@
 	 * task's user address space, so we can switch on the
 	 * interrupts again and then search the VMAs
 	 */
-
 	__sti();
 
         down_read(&mm->mmap_sem);
@@ -186,30 +217,20 @@
  * we can handle it..
  */
 good_area:
-        write = 0;
 	si_code = SEGV_ACCERR;
+	if (error_code != 4) {
+		/* page not present, check vm flags */
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+			goto bad_area;
+	}
 
-        switch (error_code & 0xFF) {
-                case 0x04:                                /* write, present*/
-                        write = 1;
-                        break;
-                case 0x10:                                   /* not present*/
-                case 0x11:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-                                goto bad_area;
-                        break;
-                default:
-                       printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
-                       goto bad_area;
-        }
-
- survive:
+survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, write)) {
+	switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
 	case 1:
 		tsk->min_flt++;
 		break;
@@ -236,22 +257,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
-#ifndef CONFIG_SYSCTL
-#ifdef CONFIG_PROCESS_DEBUG
-                printk("User process fault: interruption code 0x%lX\n",error_code);
-                printk("failing address: %lX\n",address);
-		show_regs(regs);
-#endif
-#else
-		if (sysctl_userprocess_debug) {
-			printk("User process fault: interruption code 0x%lX\n",
-			       error_code);
-			printk("failing address: %lX\n", address);
-			show_regs(regs);
-		}
-#endif
-
-		force_sigsegv(tsk, si_code, (void *)address);
+		force_sigsegv(regs, error_code, si_code, address);
                 return;
 	}
 
@@ -266,8 +272,7 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
-
-        if (kernel_address)
+        if (user_address == 0)
                 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
         	       " at virtual kernel address %08lx\n", address);
         else
@@ -311,17 +316,20 @@
 		goto no_context;
 }
 
-/*
- * Send SIGSEGV to task.  This is an external routine
- * to keep the stack usage of do_page_fault small.
- */
-static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
 {
-	struct siginfo si;
-	si.si_signo = SIGSEGV;
-	si.si_code = code;
-	si.si_addr = address;
-	force_sig_info(SIGSEGV, &si, tsk);
+	regs->psw.addr -= (error_code >> 16);
+	do_exception(regs, 4);
+}
+
+void do_segment_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x10);
+}
+
+void do_page_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x11);
 }
 
 typedef struct _pseudo_wait_t {
@@ -343,7 +351,6 @@
         pseudo_wait_t wait_struct;
         pseudo_wait_t *ptr, *last, *next;
         unsigned long address;
-        int kernel_address;
 
         /*
          * get the failing address
@@ -393,21 +400,7 @@
 			 * while we are running disabled. VM will then swap
 			 * in the page synchronously.
                          */
-			kernel_address = 0;
-                         switch (S390_lowcore.trans_exc_code & 3) {
-                         case 0: /* Primary Segment Table Descriptor */
-                                 kernel_address = 1;
-                                 break;
-                         case 1: /* STD determined via access register */
-                                 if (S390_lowcore.exc_access_id == 0 ||
-                                     regs->acrs[S390_lowcore.exc_access_id]==0)
-                                         kernel_address = 1;
-                                 break;
-                         case 2: /* Secondary Segment Table Descriptor */
-                         case 3: /* Home Segment Table Descriptor */
-                                 break;
-                         }
-                         if (kernel_address)
+                         if (check_user_space(regs, error_code) == 0)
                                  /* dereference a virtual kernel address */
                                  __asm__ __volatile__ (
                                          "  ic 0,0(%0)"
diff -urN linux-2.4.19-pre2/arch/s390x/Makefile linux-2.4.19-pre3/arch/s390x/Makefile
--- linux-2.4.19-pre2/arch/s390x/Makefile	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/Makefile	Mon Mar 11 14:13:27 2002
@@ -60,6 +60,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
+	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
 
diff -urN linux-2.4.19-pre2/arch/s390x/boot/install.sh linux-2.4.19-pre3/arch/s390x/boot/install.sh
--- linux-2.4.19-pre2/arch/s390x/boot/install.sh	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/arch/s390x/boot/install.sh	Mon Mar 11 14:13:27 2002
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/s390x/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for s390 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+	mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+	mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
diff -urN linux-2.4.19-pre2/arch/s390x/config.in linux-2.4.19-pre3/arch/s390x/config.in
--- linux-2.4.19-pre2/arch/s390x/config.in	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/config.in	Mon Mar 11 14:13:27 2002
@@ -6,8 +6,8 @@
 define_bool CONFIG_ISA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 mainmenu_name "Linux Kernel Configuration"
diff -urN linux-2.4.19-pre2/arch/s390x/defconfig linux-2.4.19-pre3/arch/s390x/defconfig
--- linux-2.4.19-pre2/arch/s390x/defconfig	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/defconfig	Mon Mar 11 14:13:27 2002
@@ -4,8 +4,8 @@
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_GENERIC_BUST_SPINLOCK is not set
 CONFIG_ARCH_S390=y
 CONFIG_ARCH_S390X=y
@@ -131,8 +131,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -144,10 +142,10 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
-# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -165,7 +163,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
+CONFIG_NET_FASTROUTE=y
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/Makefile linux-2.4.19-pre3/arch/s390x/kernel/Makefile
--- linux-2.4.19-pre2/arch/s390x/kernel/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/s390x/kernel/Makefile	Mon Mar 11 14:13:27 2002
@@ -10,7 +10,7 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
-all: kernel.o head.o init_task.o
+all: asm-offsets.h kernel.o head.o init_task.o
 
 O_TARGET	:= kernel.o
 
@@ -32,9 +32,31 @@
 obj-$(CONFIG_S390_SUPPORT)	+= linux32.o signal32.o ioctl32.o wrapper32.o exec32.o
 obj-$(CONFIG_BINFMT_ELF32)	+= binfmt_elf32.o
 
+.PHONY: asm-offsets.h
+
 #
 # This is just to get the dependencies...
 #
 binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
 
+#
+# Automatic offset generation for assembler files.
+#
+asm-offsets.h: asm-offsets.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \
+	(echo "#ifndef __ASM_OFFSETS_H__"; \
+	 echo "#define __ASM_OFFSETS_H__"; \
+	 echo "/*"; \
+	 echo " * DO NOT MODIFY"; \
+	 echo " *"; \
+	 echo " * This file was generated by arch/s390/kernel/Makefile"; \
+	 echo " */"; \
+	 sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \
+	     -e "s:->::"; \
+	 echo "#endif" \
+	) > asm-offsets.h
+
+clean:
+	rm -f asm-offsets.h
+
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/asm-offsets.c linux-2.4.19-pre3/arch/s390x/kernel/asm-offsets.c
--- linux-2.4.19-pre2/arch/s390x/kernel/asm-offsets.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/arch/s390x/kernel/asm-offsets.c	Mon Mar 11 14:13:27 2002
@@ -0,0 +1,32 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val, marker) \
+	asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),);
+	DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),);
+	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
+	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+	BLANK();
+	DEFINE(__TASK_state, offsetof(struct task_struct, state),);
+	DEFINE(__TASK_sigpending, offsetof(struct task_struct, sigpending),);
+	DEFINE(__TASK_need_resched,
+	       offsetof(struct task_struct, need_resched),);
+	DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),);
+	DEFINE(__TASK_processor, offsetof(struct task_struct, processor),);
+
+	return 0;
+}
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/entry.S linux-2.4.19-pre3/arch/s390x/kernel/entry.S
--- linux-2.4.19-pre2/arch/s390x/kernel/entry.S	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/entry.S	Mon Mar 11 14:13:27 2002
@@ -18,6 +18,7 @@
 #include <asm/smp.h>
 #include <asm/ptrace.h>
 
+#include "asm-offsets.h"
 
 /*
  * Stack layout for the system_call stack entry.
@@ -45,41 +46,7 @@
 SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
 /* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
-#if CONFIG_REMOTE_DEBUG
-SP_CRREGS    =  (SP_TRAP+4)
-/* fpu registers are saved & restored by the gdb stub itself */
-SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
-SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
-#else
-SP_PGM_OLD_ILC= (SP_TRAP+4)
-#endif
-SP_SIZE      =  (SP_PGM_OLD_ILC+4)
-/*
- * these defines are offsets into the thread_struct
- */
-_TSS_PTREGS  = 0
-_TSS_FPRS    = (_TSS_PTREGS+8)
-_TSS_AR2     = (_TSS_FPRS+136)
-_TSS_AR4     = (_TSS_AR2+4)
-_TSS_KSP     = (_TSS_AR4+4)
-_TSS_USERSEG = (_TSS_KSP+8)
-_TSS_PROT    = (_TSS_USERSEG+8)
-_TSS_ERROR   = (_TSS_PROT+8)
-_TSS_TRAP    = (_TSS_ERROR+4)
-_TSS_PER     = (_TSS_TRAP+4)
-_TSS_IEEE    = (_TSS_PER+72)
-_TSS_FLAGS   = (_TSS_IEEE+8)
-
-/*
- * these are offsets into the task-struct.
- */
-state        =  0
-flags        =  8
-sigpending   = 16
-need_resched = 32
-tsk_ptrace   = 40
-processor    = 88
+SP_SIZE      =  (SP_TRAP+4)
 
 /*
  * Register usage in interrupt handlers:
@@ -136,37 +103,31 @@
 
 /*
  * Scheduler resume function, called by switch_to
- *  grp2 = (thread_struct *) prev->tss
- *  grp3 = (thread_struct *) next->tss
+ *  gpr2 = (task_struct *) prev
+ *  gpr3 = (task_struct *) next
  * Returns:
  *  gpr2 = prev
  */
         .globl  resume
 resume:
-        lg      %r4,_TSS_PTREGS(%r3)
-        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
-        jz      resume_noper            # if not we're fine
+	tm	__THREAD_per+4(%r3),0xe8	# is the new process using per ?
+	jz	resume_noper		# if not we're fine
         stctg   %c9,%c11,48(%r15)       # We are using per stuff
-        clc     _TSS_PER(24,%r3),48(%r15)
+        clc     __THREAD_per(24,%r3),48(%r15)
         je      resume_noper            # we got away without bashing TLB's
-        lctlg   %c9,%c11,_TSS_PER(%r3)  # Nope we didn't
+        lctlg   %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 resume_noper:
         stmg    %r6,%r15,48(%r15)       # store resume registers of prev task
-        stg     %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
-        lghi    %r0,-16384
-        ngr     %r0,%r15
-        lg      %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
-        lghi    %r1,16383
-        ogr     %r1,%r15
-        aghi    %r1,1
-        stg     %r1,__LC_KERNEL_STACK   # __LC_KERNEL_STACK = new kernel stack
-        stam    %a2,%a2,_TSS_AR2(%r2)   # store kernel access reg. 2
-        stam    %a4,%a4,_TSS_AR4(%r2)   # store kernel access reg. 4
-        lam     %a2,%a2,_TSS_AR2(%r3)   # load kernel access reg. 2
-        lam     %a4,%a4,_TSS_AR4(%r3)   # load kernel access reg. 4
-        lgr     %r2,%r0                 # return task_struct of last task
+	stg	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
+	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
+        stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
+        stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
+        lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
+        lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
         lmg     %r6,%r15,48(%r15)       # load resume registers of next task
-        br      %r14
+	aghi	%r3,16384
+	stg	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
+	br	%r14
 
 /*
  * do_softirq calling function. We want to run the softirq functions on the
@@ -195,19 +156,17 @@
 	.globl  system_call
 system_call:
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
-pgm_system_call:
-        GET_CURRENT               # load pointer to task_struct to R9
 	larl    %r7,sys_call_table
-	llgc    %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore
-	stosm   48(%r15),0x03     # reenable interrupts
+	llgh    %r8,__LC_SVC_INT_CODE # get svc number from lowcore
         sll     %r8,3
+        GET_CURRENT               # load pointer to task_struct to R9
+	stosm   48(%r15),0x03     # reenable interrupts
         tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
         jo      sysc_noemu
 	la      %r8,4(%r8)        # use 31 bit emulation system calls
 sysc_noemu:
         lgf     %r8,0(%r8,%r7)    # load address of system call routine
-        tm      tsk_ptrace+7(%r9),0x02 # PT_TRACESYS
+        tm      __TASK_ptrace+7(%r9),0x02 # PT_TRACESYS
         jnz     sysc_tracesys
         basr    %r14,%r8          # call sys_xxxx
         stg     %r2,SP_R2(%r15)   # store return value (change R2 on stack)
@@ -220,14 +179,12 @@
 #
 # check, if reschedule is needed
 #
-	lg      %r0,need_resched(%r9) # get need_resched from task_struct
+	lg      %r0,__TASK_need_resched(%r9)
 	ltgr    %r0,%r0
         jnz     sysc_reschedule
-        icm     %r0,15,sigpending(%r9)     # get sigpending from task_struct
+        icm     %r0,15,__TASK_sigpending(%r9)
         jnz     sysc_signal_return
 sysc_leave:
-        tm      SP_PGM_OLD_ILC(%r15),0xff
-        jz      pgm_svcret
 	stnsm   48(%r15),0xfc         # disable I/O and ext. interrupts
         RESTORE_ALL 1
 
@@ -241,38 +198,44 @@
 	jg      do_signal           # return point is sysc_leave
 
 #
+# call schedule with sysc_return as return-address
+#
+sysc_reschedule:        
+	larl    %r14,sysc_return
+        jg      schedule            # return point is sysc_return
+#
 # call trace before and after sys_call
 #
 sysc_tracesys:
-	lghi    %r2,-ENOSYS
-	stg     %r2,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+	larl	%r12,sysc_return
+
+#
+# call syscall_trace before and after system call
+# special linkage: %r12 contains the return address for trace_svc
+#
+trace_svc:
+	lghi    %r7,-ENOSYS
+	stg     %r7,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
         brasl   %r14,syscall_trace
 	lg      %r2,SP_R2(%r15)
 	cghi    %r2,-ENOSYS
-	je      sysc_tracesys_dn1   
+	je      trace_svc_go
 	sllg    %r2,%r2,56          # strace wants to change the syscall
 	srlg    %r2,%r2,53          # zap unused bits & multiply by 8
 	tm      SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
-        jo      sysc_tracesys_noemu
+        jo      trace_svc_noemu
 	la      %r2,4(%r2)          # use 31 bit emulation system calls
-sysc_tracesys_noemu:
+trace_svc_noemu:
 	lgf	%r8,0(%r2,%r7)      # load address of system call routine
-sysc_tracesys_dn1:	
+trace_svc_go:	
 	lmg     %r3,%r6,SP_R3(%r15)
 	lg      %r2,SP_ORIG_R2(%r15)
         basr    %r14,%r8            # call sys_xxx
         stg     %r2,SP_R2(%r15)     # store return value
-	larl    %r14,sysc_return
+	lgr	%r14,%r12	    # return point is in %r12
         jg      syscall_trace       # return point is sysc_return
 
 #
-# call schedule with sysc_return as return-address
-#
-sysc_reschedule:        
-	larl    %r14,sysc_return
-        jg      schedule            # return point is sysc_return
-
-#
 # a new process exits the kernel with ret_from_fork
 #
         .globl  ret_from_fork
@@ -280,12 +243,8 @@
         GET_CURRENT               # load pointer to task_struct to R9
         stosm   48(%r15),0x03     # reenable interrupts
 	xc      SP_R2(8,%r15),SP_R2(%r15) # child returns 0
-#ifdef CONFIG_SMP
 	larl    %r14,sysc_return
         jg      schedule_tail     # return to sysc_return
-#else
-        j       sysc_return
-#endif
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
@@ -630,11 +589,24 @@
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
 	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for posix_acl */
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for posix_acl */
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */
-        .rept  255-224
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for gettid */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for tkill */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr  */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 226 - reserved for fsetxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 227 - reserved for getxattr  */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 228 - reserved for lgetxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 229 - reserved for fgetxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 230 - reserved for listxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 231 - reserved for llistxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 232 - reserved for flistxattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 233 - reserved for removexattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 234 - reserved for lremovexattr */
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 235 - reserved for fremovexattr */
+	.rept  255-235
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+	.long  SYSCALL(sys_gettid,sys_gettid)
+	.long  SYSCALL(sys_tkill,sys_tkill)
 	.endr
 
 /*
@@ -657,51 +629,91 @@
  * for LPSW?).
  */
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
-        jz      pgm_sv                   # skip if not
+        jnz     pgm_per                  # got per exception -> special case
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+	llgh    %r8,__LC_PGM_INT_CODE
+        sll     %r8,3
+	GET_CURRENT
+        larl    %r1,pgm_check_table
+        lg      %r1,0(%r8,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+	larl	%r14,sysc_return
+        br      %r1			 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
-        jnz     pgm_sv                   # skip if it is
+        jnz     pgm_per_std              # ok, normal per event from user space
 # ok its one of the special cases, now we need to find out which one
         clc     __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
         je      pgm_svcper
 # no interesting special case, ignore PER event
 	lpswe   __LC_PGM_OLD_PSW
+
+#
+# Normal per exception
+#
+pgm_per_std:
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+	GET_CURRENT
+	lghi    %r4,0x7f
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+        nr      %r4,%r3			 # clear per-event-bit and ilc
+        je      pgm_per_only		 # only per of per+check ?
+        sll     %r4,3
+        larl    %r1,pgm_check_table
+        lg      %r1,0(%r4,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+        basr    %r14,%r1		 # branch to interrupt-handler
+pgm_per_only:
+        la      %r2,SP_PTREGS(15)	 # address of register-save area
+        larl    %r14,sysc_return	 # load adr. of system return
+        jg      handle_per_exception
+
+#
 # it was a single stepped SVC that is causing all the trouble
+#
 pgm_svcper:
 	SAVE_ALL __LC_SVC_OLD_PSW,1
-        mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
-        j       pgm_system_call          # now do the svc
+	larl    %r7,sys_call_table
+	llgh    %r8,__LC_SVC_INT_CODE # get svc number from lowcore
+        sll     %r8,3
+        GET_CURRENT               # load pointer to task_struct to R9
+	stosm   48(%r15),0x03     # reenable interrupts
+        tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
+        jo      pgm_svcper_noemu
+	la      %r8,4(%r8)        # use 31 bit emulation system calls
+pgm_svcper_noemu:
+        lgf     %r8,0(%r8,%r7)    # load address of system call routine
+        tm      __TASK_ptrace+7(%r9),0x02 # PT_TRACESYS
+        jnz     pgm_tracesys
+        basr    %r14,%r8          # call sys_xxxx
+        stg     %r2,SP_R2(%r15)   # store return value (change R2 on stack)
+                                  # ATTENTION: check sys_execve_glue before
+                                  # changing anything here !!
+
 pgm_svcret:
+        icm     %r0,15,__TASK_sigpending(%r9)
+        jz      pgm_svcper_nosig
+        la      %r2,SP_PTREGS(%r15) # load pt_regs
+        sgr     %r3,%r3             # clear *oldset
+	brasl	%r14,do_signal
+	
+pgm_svcper_nosig:
 	lhi     %r0,__LC_PGM_OLD_PSW     # set trap indication back to pgm_chk
 	st      %r0,SP_TRAP(%r15)
-        llgh    %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-	j       pgm_no_sv
-pgm_sv:
-	SAVE_ALL __LC_PGM_OLD_PSW,1
-        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-        llgh    %r7,__LC_PGM_ILC         # load instruction length
-	GET_CURRENT
-pgm_no_sv:
-        llgh    %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-	lghi    %r3,0x7f
-        nr      %r3,%r8           # clear per-event-bit & move to r3
-        je      pgm_dn            # none of Martins exceptions occurred bypass
-        sll     %r3,3
-        larl    %r1,pgm_check_table
-        lg      %r1,0(%r3,%r1)    # load address of handler routine
-        srl     %r3,3
-        la      %r2,SP_PTREGS(%r15) # address of register-save area
-        chi     %r3,0x4           # protection-exception ?
-        jne     pgm_go            # if not,
-        lg      %r5,SP_PSW+8(15)  # load psw addr
-        slgr    %r5,%r7           # substract ilc from psw
-        stg     %r5,SP_PSW+8(15)  # store corrected psw addr
-pgm_go: basr    %r14,%r1          # branch to interrupt-handler
-pgm_dn: nill    %r8,0x80          # check for per exception
-        je      sysc_return
         la      %r2,SP_PTREGS(15) # address of register-save area
         larl    %r14,sysc_return  # load adr. of system return
         jg      handle_per_exception
+#
+# call trace before and after sys_call
+#
+pgm_tracesys:
+	larl	%r12,pgm_svcret
+	j	trace_svc
 
 /*
  * IO interrupt handler routine
@@ -720,7 +732,7 @@
 #
 # check, if bottom-half has to be done
 #
-	lgf     %r1,processor(%r9)    # get cpu number from task struture
+	lgf     %r1,__TASK_processor(%r9)
 	larl    %r2,irq_stat
 	sll     %r1,L1_CACHE_SHIFT
 	la      %r1,0(%r1,%r2)
@@ -734,10 +746,10 @@
 #
 # check, if reschedule is needed
 #
-	lg      %r0,need_resched(%r9)  # get need_resched from task_struct
+	lg      %r0,__TASK_need_resched(%r9)
 	ltgr    %r0,%r0
         jnz     io_reschedule
-        icm     %r0,15,sigpending(%r9) # get sigpending from task_struct
+        icm     %r0,15,__TASK_sigpending(%r9)
         jnz     io_signal_return
 io_leave:
         stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/irq.c linux-2.4.19-pre3/arch/s390x/kernel/irq.c
--- linux-2.4.19-pre2/arch/s390x/kernel/irq.c	Wed Jul 25 14:12:01 2001
+++ linux-2.4.19-pre3/arch/s390x/kernel/irq.c	Mon Mar 11 14:13:27 2002
@@ -59,60 +59,6 @@
 BUILD_SMP_INTERRUPT(spurious_interrupt)
 #endif
 
-#if 0
-int get_irq_list(char *buf)
-{
-	int i, j;
-	struct irqaction * action;
-	char *p = buf;
-
-	p += sprintf(p, "           ");
-
-	for (j=0; j<smp_num_cpus; j++)
-		p += sprintf(p, "CPU%d       ",j);
-
-	*p++ = '\n';
-
-	for (i = 0 ; i < NR_IRQS ; i++)
-	{
-		if (ioinfo[i] == INVALID_STORAGE_AREA)
-			continue;
-
-		action = ioinfo[i]->irq_desc.action;
-		
-  		if (!action)
-			continue;
-
-		p += sprintf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-		p += sprintf(p, "%10u ", kstat_irqs(i));
-#else
-		for (j=0; j<smp_num_cpus; j++)
-			p += sprintf( p, "%10u ",
-			              kstat.irqs[cpu_logical_map(j)][i]);
-#endif
-		p += sprintf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
-		p += sprintf(p, "  %s", action->name);
-
-		for (action=action->next; action; action = action->next)
-		{
-			p += sprintf(p, ", %s", action->name);
-
-		} /* endfor */
-
-		*p++ = '\n';
-	
-	} /* endfor */
-
-	p += sprintf(p, "NMI: %10u\n", nmi_counter);
-#ifdef CONFIG_SMP
-	p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
-#endif
-
-	return p - buf;
-}
-#endif
-
 /*
  * Global interrupt locks for SMP. Allow interrupts to come in on any
  * CPU, yet make cli/sti act globally to protect critical regions..
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/linux32.c linux-2.4.19-pre3/arch/s390x/kernel/linux32.c
--- linux-2.4.19-pre2/arch/s390x/kernel/linux32.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/linux32.c	Mon Mar 11 14:13:27 2002
@@ -288,6 +288,21 @@
 
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
+struct ipc64_perm_ds32
+{
+        __kernel_key_t          key;
+        __kernel_uid32_t        uid;
+        __kernel_gid32_t        gid;
+        __kernel_uid32_t        cuid;
+        __kernel_gid32_t        cgid;
+        __kernel_mode_t32       mode;
+        unsigned short          __pad1;
+        unsigned short          seq;
+        unsigned short          __pad2;
+        unsigned int            __unused1;
+        unsigned int            __unused2;
+};
+
 struct ipc_perm32
 {
 	key_t    	  key;
@@ -311,7 +326,7 @@
 };
 
 struct semid64_ds32 {
-	struct ipc64_perm sem_perm;		  /* this structure is the same on sparc32 and sparc64 */
+	struct ipc64_perm_ds32 sem_perm;
 	unsigned int	  __pad1;
 	__kernel_time_t32 sem_otime;
 	unsigned int	  __pad2;
@@ -339,7 +354,7 @@
 };
 
 struct msqid64_ds32 {
-	struct ipc64_perm msg_perm;
+	struct ipc64_perm_ds32 msg_perm;
 	unsigned int   __pad1;
 	__kernel_time_t32 msg_stime;
 	unsigned int   __pad2;
@@ -368,7 +383,7 @@
 };
 
 struct shmid64_ds32 {
-	struct ipc64_perm	shm_perm;
+	struct ipc64_perm_ds32	shm_perm;
 	unsigned int		__pad1;
 	__kernel_time_t32	shm_atime;
 	unsigned int		__pad2;
@@ -1390,7 +1405,7 @@
 
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
-		time_t sec, usec;
+		int sec, usec;
 
 		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
 		    || (ret = __get_user(sec, &tvp->tv_sec))
@@ -1442,7 +1457,7 @@
 	ret = do_select(n, &fds, &timeout);
 
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
+		int sec = 0, usec = 0;
 		if (timeout) {
 			sec = timeout / HZ;
 			usec = timeout % HZ;
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/process.c linux-2.4.19-pre3/arch/s390x/kernel/process.c
--- linux-2.4.19-pre2/arch/s390x/kernel/process.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/process.c	Mon Mar 11 14:13:27 2002
@@ -50,28 +50,37 @@
  * The idle loop on a S390...
  */
 
-static psw_t wait_psw;
-
 int cpu_idle(void *unused)
 {
+	psw_t wait_psw;
+	unsigned long reg;
+
 	/* endless idle loop with no priority at all */
         init_idle();
 	current->nice = 20;
 	current->counter = -100;
-	wait_psw.mask = _WAIT_PSW_MASK;
-	wait_psw.addr = (unsigned long) &&idle_wakeup;
-	while(1) {
-                if (current->need_resched) {
-                        schedule();
-                        check_pgt_cache();
-                        continue;
-                }
-
-		/* load wait psw */
+	while (1) {
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+			continue;
+		}
+
+		/* 
+		 * Wait for external, I/O or machine check interrupt and
+		 * switch of machine check bit after the wait has ended.
+		 */
+		wait_psw.mask = _WAIT_PSW_MASK;
 		asm volatile (
-                        "lpswe %0"
-                        : : "m" (wait_psw) );
-idle_wakeup:
+			"    larl  %0,0f\n"
+			"    stg   %0,8(%1)\n"
+			"    lpswe 0(%1)\n"
+			"0:  larl  %0,1f\n"
+			"    stg   %0,8(%1)\n"
+			"    ni    1(%1),0xf9\n"
+			"    lpswe 0(%1)\n"
+			"1:"
+			: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
 	}
 }
 
@@ -165,8 +174,7 @@
         frame->gprs[8] = (unsigned long) &ret_from_fork;
 
         /* fake return stack for resume(), don't go back to schedule */
-        frame->gprs[9]  = (unsigned long) frame;
-	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
+        frame->gprs[9] = (unsigned long) frame;
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/reipl.S linux-2.4.19-pre3/arch/s390x/kernel/reipl.S
--- linux-2.4.19-pre2/arch/s390x/kernel/reipl.S	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/arch/s390x/kernel/reipl.S	Mon Mar 11 14:13:27 2002
@@ -21,8 +21,10 @@
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
         	msch    .Lschib-.Lpg0(%r13) 
-		ssch	.Liplorb-.Lpg0(%r13)           
-		jz	.L001   
+	        lghi    %r0,5
+.Lssch:		ssch	.Liplorb-.Lpg0(%r13)           
+		jz	.L001
+		brct    %r0,.Lssch   
 		bas	%r14,.Ldisab-.Lpg0(%r13)
 .L001:		mvc	__LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpswe	.Lwaitpsw-.Lpg0(%r13)          
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/s390_ksyms.c linux-2.4.19-pre3/arch/s390x/kernel/s390_ksyms.c
--- linux-2.4.19-pre2/arch/s390x/kernel/s390_ksyms.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/s390_ksyms.c	Mon Mar 11 14:13:27 2002
@@ -7,6 +7,7 @@
 #include <linux/highuid.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/setup.c linux-2.4.19-pre3/arch/s390x/kernel/setup.c
--- linux-2.4.19-pre2/arch/s390x/kernel/setup.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/setup.c	Mon Mar 11 14:13:27 2002
@@ -48,7 +48,7 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
-struct { unsigned long addr, size, type; } memory_chunk[16];
+struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
 #define CHUNK_READ_WRITE 0
 #define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
@@ -283,8 +283,8 @@
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
-	       "We are running under VM\n" :
-	       "We are running native\n");
+	       "We are running under VM (64 bit mode)\n" :
+	       "We are running native (64 bit mode)\n");
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
@@ -485,7 +485,7 @@
 				(loops_per_jiffy/(5000/HZ))%100);
 	}
 	if (cpu_online_map & (1 << n)) {
-		cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
+		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
 		seq_printf(m, "processor %i: "
 				"version = %02X,  "
 				"identification = %06X,  "
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/signal.c linux-2.4.19-pre3/arch/s390x/kernel/signal.c
--- linux-2.4.19-pre2/arch/s390x/kernel/signal.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/s390x/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -66,17 +66,15 @@
 		err = __put_user(from->si_signo, &to->si_signo);
 		err |= __put_user(from->si_errno, &to->si_errno);
 		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
+		/* First 64bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
+		err |= __put_user(from->si_uid, &to->si_uid);
 		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
 		case __SI_CHLD >> 16:
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
 			err |= __put_user(from->si_status, &to->si_status);
 		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
 			break;
 		/* case __SI_RT: This is not generated by the kernel as of now.  */
 		}
@@ -569,10 +567,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/signal32.c linux-2.4.19-pre3/arch/s390x/kernel/signal32.c
--- linux-2.4.19-pre2/arch/s390x/kernel/signal32.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre3/arch/s390x/kernel/signal32.c	Mon Mar 11 14:13:27 2002
@@ -30,7 +30,7 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-#define _USER_PSW_MASK32 0x0701C00080000000
+#define _USER_PSW_MASK32 0x0705C00080000000
 
 typedef struct 
 {
@@ -699,10 +699,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/smp.c linux-2.4.19-pre3/arch/s390x/kernel/smp.c
--- linux-2.4.19-pre2/arch/s390x/kernel/smp.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/smp.c	Mon Mar 11 14:13:27 2002
@@ -191,7 +191,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_restart);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_restart();
 }
@@ -208,7 +209,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_halt);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_halt();
 }
@@ -225,7 +227,8 @@
 {
         if (smp_processor_id() != 0) {
                 smp_ext_bitcall(0, ec_power_off);
-                for (;;);
+		for (;;)
+			enabled_wait();
         } else
                 do_machine_power_off();
 }
@@ -270,7 +273,7 @@
         /*
          * Set signaling bit in lowcore of target cpu and kick it
          */
-	set_bit(sig, &(get_cpu_lowcore(cpu).ext_call_fast));
+	set_bit(sig, &(get_cpu_lowcore(cpu)->ext_call_fast));
         ccode = signal_processor(cpu, sigp_external_call);
         return ccode;
 }
@@ -290,8 +293,9 @@
                 /*
                  * Set signaling bit in lowcore of target cpu and kick it
                  */
-		set_bit(sig, &(get_cpu_lowcore(i).ext_call_fast));
-                ccode = signal_processor(i, sigp_external_call);
+		set_bit(sig, &(get_cpu_lowcore(i)->ext_call_fast));
+                while (signal_processor(i, sigp_external_call) == sigp_busy)
+			udelay(10);
         }
 }
 
@@ -308,7 +312,7 @@
 
         /* write magic number to zero page (absolute 0) */
 
-        get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
 
         /* stop all processors */
 
@@ -330,7 +334,7 @@
         for (i =  0; i < smp_num_cpus; i++) {
                 if (smp_processor_id() != i) {
                         int ccode;
-                        low_core_addr = (unsigned long)&get_cpu_lowcore(i);
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
                         do {
                                 ccode = signal_processor_ps(
                                    &dummy,
@@ -432,6 +436,7 @@
 
         current->processor = 0;
         smp_num_cpus = 1;
+        cpu_online_map = 1;
         for (curr_cpu = 0;
              curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
                 if ((__u16) curr_cpu == boot_cpu_addr)
@@ -458,7 +463,7 @@
         /* Setup the cpu */
         cpu_init();
         /* Print info about this processor */
-        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data);
         /* Wait for completion of smp startup */
         while (!atomic_read(&smp_commenced))
                 /* nothing */ ;
@@ -514,7 +519,7 @@
         unhash_process(idle);
         init_tasks[cpu] = idle;
 
-        cpu_lowcore=&get_cpu_lowcore(cpu);
+        cpu_lowcore = get_cpu_lowcore(cpu);
 	cpu_lowcore->save_area[15] = idle->thread.ksp;
 	cpu_lowcore->kernel_stack = (__u64) idle + 16384;
         __asm__ __volatile__("la    1,%0\n\t"
@@ -569,7 +574,7 @@
         /*
          *      Initialize the logical to physical CPU number mapping
          */
-        print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data);
 
         for(i = 0; i < smp_num_cpus; i++)
         {
@@ -627,3 +632,4 @@
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/time.c linux-2.4.19-pre3/arch/s390x/kernel/time.c
--- linux-2.4.19-pre2/arch/s390x/kernel/time.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/time.c	Mon Mar 11 14:13:27 2002
@@ -55,7 +55,7 @@
 {
 	__u64 now;
 
-	asm ("STCK %0" : "=m" (now));
+	asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
         now = (now - init_timer_cc) >> 12;
 	/* We require the offset from the latest update of xtime */
 	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
@@ -173,9 +173,10 @@
 	int cc;
 
         /* kick the TOD clock */
-        asm volatile ("STCK %1\n\t"
+        asm volatile ("STCK 0(%1)\n\t"
                       "IPM  %0\n\t"
-                      "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
+                      "SRL  %0,28" : "=r" (cc) : "a" (&init_timer_cc) 
+				   : "memory", "cc");
         switch (cc) {
         case 0: /* clock in set state: all is fine */
                 break;
diff -urN linux-2.4.19-pre2/arch/s390x/kernel/traps.c linux-2.4.19-pre3/arch/s390x/kernel/traps.c
--- linux-2.4.19-pre2/arch/s390x/kernel/traps.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre3/arch/s390x/kernel/traps.c	Mon Mar 11 14:13:27 2002
@@ -52,7 +52,10 @@
 #endif
 #endif
 
-extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_segment_exception;
+extern pgm_check_handler_t do_region_exception;
+extern pgm_check_handler_t do_page_exception;
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
 extern void pfault_fini(void);
@@ -270,23 +273,6 @@
         do_exit(SIGSEGV);
 }
 
-#define DO_ERROR(signr, str, name) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-	do_trap(interruption_code, signr, str, regs, NULL); \
-}
-
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-        siginfo_t info; \
-        info.si_signo = signr; \
-        info.si_errno = 0; \
-        info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
-}
-
 static void inline do_trap(long interruption_code, int signr, char *str,
                            struct pt_regs *regs, siginfo_t *info)
 {
@@ -299,7 +285,7 @@
 
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 struct task_struct *tsk = current;
-                tsk->thread.trap_no = interruption_code;
+                tsk->thread.trap_no = interruption_code & 0xffff;
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -326,6 +312,11 @@
         }
 }
 
+static inline void *get_check_address(struct pt_regs *regs)
+{
+	return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+}
+
 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
 	if(regs->psw.mask&PSW_PROBLEM_STATE)
@@ -349,15 +340,70 @@
 	return 0;
 }
 
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+        siginfo_t info; \
+        info.si_signo = signr; \
+        info.si_errno = 0; \
+        info.si_code = sicode; \
+        info.si_addr = (void *)siaddr; \
+        do_trap(interruption_code, signr, str, regs, &info); \
+}
+
 DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
-DO_ERROR(SIGILL,  "privileged operation", privileged_op)
-DO_ERROR(SIGILL,  "execute exception", execute_exception)
-DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
-DO_ERROR(SIGILL,  "translation exception", translation_exception)
-DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
-DO_ERROR(SIGILL,  "operand exception", operand_exception)
-DO_ERROR(SIGILL,  "specification exception", specification_exception);
+
+DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
+	      BUS_ADRERR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
+	      FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
+	      ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "specification exception", specification_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void *location,
+           int fpc, long interruption_code)
+{
+	siginfo_t si;
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_addr = location;
+	si.si_code = 0;
+	/* FPC[2] is Data Exception Code */
+	if ((fpc & 0x00000300) == 0) {
+		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
+		if (fpc & 0x8000) /* invalid fp operation */
+			si.si_code = FPE_FLTINV;
+		else if (fpc & 0x4000) /* div by 0 */
+			si.si_code = FPE_FLTDIV;
+		else if (fpc & 0x2000) /* overflow */
+			si.si_code = FPE_FLTOVF;
+		else if (fpc & 0x1000) /* underflow */
+			si.si_code = FPE_FLTUND;
+		else if (fpc & 0x0800) /* inexact */
+			si.si_code = FPE_FLTRES;
+	}
+	current->thread.ieee_instruction_pointer = (addr_t) location;
+	do_trap(interruption_code, SIGFPE,
+		"floating point exception", regs, &si);
+}
 
 asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
@@ -365,7 +411,7 @@
 	__u16 *location;
 	int do_sig = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -390,15 +436,15 @@
 	else
 		do_sig = 1;
 	if (do_sig)
-		do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
+		do_trap(interruption_code, SIGILL,
+			"illegal operation", regs, NULL);
 }
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 {
 	__u16 *location;
-	int do_sig = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -409,17 +455,19 @@
 
 	__asm__ volatile ("stfpc %0\n\t" 
 			  : "=m" (current->thread.fp_regs.fpc));
-	/* Same code should work when we implement fpu emulation */
-	/* provided we call data exception from the fpu emulator */
-	if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
-	{
-		current->thread.ieee_instruction_pointer=(addr_t)location;
-		force_sig(SIGFPE, current);
+
+	if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else {
+		siginfo_t info;
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, SIGILL, 
+			"data exception", regs, &info);
 	}
-	else
-		do_sig = 1;
-        if (do_sig)
-                do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
 }
 
 
@@ -435,6 +483,7 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
+        pgm_check_table[4] = &do_protection_exception;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
@@ -442,12 +491,11 @@
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
         pgm_check_table[0x15] = &operand_exception;
-        pgm_check_table[4] = &do_page_fault;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
+        pgm_check_table[0x10] = &do_segment_exception;
+        pgm_check_table[0x11] = &do_page_exception;
         pgm_check_table[0x1C] = &privileged_op;
         pgm_check_table[0x38] = &addressing_exception;
-        pgm_check_table[0x3B] = &do_page_fault;
+        pgm_check_table[0x3B] = &do_region_exception;
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
diff -urN linux-2.4.19-pre2/arch/s390x/mm/fault.c linux-2.4.19-pre3/arch/s390x/mm/fault.c
--- linux-2.4.19-pre2/arch/s390x/mm/fault.c	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre3/arch/s390x/mm/fault.c	Mon Mar 11 14:13:27 2002
@@ -35,7 +35,6 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
-static void force_sigsegv(struct task_struct *tsk, int code, void *address);
 
 extern spinlock_t timerlist_lock;
 
@@ -65,26 +64,96 @@
 }
 
 /*
+ * Check which address space is addressed by the access
+ * register in S390_lowcore.exc_access_id.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static int __check_access_register(struct pt_regs *regs, int error_code)
+{
+	int areg = S390_lowcore.exc_access_id;
+
+	if (areg == 0)
+		/* Access via access register 0 -> kernel address */
+		return 0;
+	if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1)
+		/*
+		 * access register contains 0 -> kernel address,
+		 * access register contains 1 -> user space address
+		 */
+		return regs->acrs[areg];
+
+	/* Something unhealthy was done with the access registers... */
+	die("page fault via unknown access register", regs, error_code);
+	do_exit(SIGKILL);
+	return 0;
+}
+
+/*
+ * Check which address space the address belongs to.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static inline int check_user_space(struct pt_regs *regs, int error_code)
+{
+	/*
+	 * The lowest two bits of S390_lowcore.trans_exc_code indicate
+	 * which paging table was used:
+	 *   0: Primary Segment Table Descriptor
+	 *   1: STD determined via access register
+	 *   2: Secondary Segment Table Descriptor
+	 *   3: Home Segment Table Descriptor
+	 */
+	int descriptor = S390_lowcore.trans_exc_code & 3;
+	if (descriptor == 1)
+		return __check_access_register(regs, error_code);
+	return descriptor >> 1;
+}
+		
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
+			  int si_code, unsigned long address)
+{
+	struct siginfo si;
+
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+#if defined(CONFIG_SYSCTL)
+	if (sysctl_userprocess_debug)
+#endif
+	{
+		printk("User process fault: interruption code 0x%lX\n",
+		       error_code);
+		printk("failing address: %lX\n", address);
+		show_regs(regs);
+	}
+#endif
+	si.si_signo = SIGSEGV;
+	si.si_code = si_code;
+	si.si_addr = (void *) address;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+/*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  *
  * error_code:
- *             ****0004       Protection           ->  Write-Protection  (suprression)
- *             ****0010       Segment translation  ->  Not present       (nullification)
- *             ****0011       Page translation     ->  Not present       (nullification)
- *             ****003B       Region third exception ->  Not present       (nullification)
+ *   04       Protection           ->  Write-Protection  (suprression)
+ *   10       Segment translation  ->  Not present       (nullification)
+ *   11       Page translation     ->  Not present       (nullification)
+ *   3b       Region third trans.  ->  Not present       (nullification)
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
 {
         struct task_struct *tsk;
         struct mm_struct *mm;
         struct vm_area_struct * vma;
         unsigned long address;
+	int user_address;
         unsigned long fixup;
-        int write;
 	int si_code = SEGV_MAPERR;
-	int kernel_address = 0;
 
         tsk = current;
         mm = tsk->mm;
@@ -94,13 +163,13 @@
 	 * as a special case because the translation exception code 
 	 * field is not guaranteed to contain valid data in this case.
 	 */
-	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+	if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) {
 
 		/* Low-address protection hit in kernel mode means 
 		   NULL pointer write access in kernel mode.  */
  		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
 			address = 0;
-			kernel_address = 1;
+			user_address = 0;
 			goto no_context;
 		}
 
@@ -114,52 +183,15 @@
          * more specific the segment and page table portion of 
          * the address 
          */
-
-        address = S390_lowcore.trans_exc_code&-4096L;
-
-
-	/*
-	 * Check which address space the address belongs to
-	 */
-	switch (S390_lowcore.trans_exc_code & 3)
-	{
-	case 0: /* Primary Segment Table Descriptor */
-		kernel_address = 1;
-		goto no_context;
-
-	case 1: /* STD determined via access register */
-		if (S390_lowcore.exc_access_id == 0)
-		{
-			kernel_address = 1;
-			goto no_context;
-		}
-		if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
-		{
-			if (regs->acrs[S390_lowcore.exc_access_id] == 0)
-			{
-				kernel_address = 1;
-				goto no_context;
-			}
-			if (regs->acrs[S390_lowcore.exc_access_id] == 1)
-			{
-				/* user space address */
-				break;
-			}
-		}
-		die("page fault via unknown access register", regs, error_code);
-        	do_exit(SIGKILL);
-		break;
-
-	case 2: /* Secondary Segment Table Descriptor */
-	case 3: /* Home Segment Table Descriptor */
-		/* user space address */
-		break;
-	}
+        address = S390_lowcore.trans_exc_code & -4096L;
+	user_address = check_user_space(regs, error_code);
 
 	/*
-	 * Check whether we have a user MM in the first place.
+	 * Verify that the fault happened in user space, that
+	 * we are not in an interrupt and that there is a 
+	 * user context.
 	 */
-        if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT))
+        if (user_address == 0 || in_interrupt() || !mm)
                 goto no_context;
 
 	/*
@@ -167,7 +199,6 @@
 	 * task's user address space, so we can switch on the
 	 * interrupts again and then search the VMAs
 	 */
-
 	__sti();
 
         down_read(&mm->mmap_sem);
@@ -186,31 +217,20 @@
  * we can handle it..
  */
 good_area:
-        write = 0;
 	si_code = SEGV_ACCERR;
+	if (error_code != 4) {
+		/* page not present, check vm flags */
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+			goto bad_area;
+	}
 
-        switch (error_code & 0xFF) {
-                case 0x04:                                /* write, present*/
-                        write = 1;
-                        break;
-                case 0x10:                                   /* not present*/
-                case 0x11:                                   /* not present*/
-                case 0x3B:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-                                goto bad_area;
-                        break;
-                default:
-                       printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
-                       goto bad_area;
-        }
-
- survive:
+survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, write)) {
+	switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
 	case 1:
 		tsk->min_flt++;
 		break;
@@ -237,22 +257,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
-#ifndef CONFIG_SYSCTL
-#ifdef CONFIG_PROCESS_DEBUG
-                printk("User process fault: interruption code 0x%lX\n",error_code);
-                printk("failing address: %lX\n",address);
-		show_regs(regs);
-#endif
-#else
-		if (sysctl_userprocess_debug) {
-			printk("User process fault: interruption code 0x%lX\n",
-			       error_code);
-			printk("failing address: %lX\n", address);
-			show_regs(regs);
-		}
-#endif
-
-		force_sigsegv(tsk, si_code, (void *)address);
+		force_sigsegv(regs, error_code, si_code, address);
                 return;
 	}
 
@@ -267,8 +272,7 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
-
-        if (kernel_address)
+        if (user_address == 0)
                 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
         	       " at virtual kernel address %016lx\n", address);
         else
@@ -312,19 +316,26 @@
 		goto no_context;
 }
 
-/*
- * Send SIGSEGV to task.  This is an external routine
- * to keep the stack usage of do_page_fault small.
- */
-static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
 {
-	struct siginfo si;
-	si.si_signo = SIGSEGV;
-	si.si_code = code;
-	si.si_addr = address;
-	force_sig_info(SIGSEGV, &si, tsk);
+	regs->psw.addr -= (error_code >> 16);
+	do_exception(regs, 4);
 }
 
+void do_segment_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x10);
+}
+
+void do_page_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x11);
+}
+
+void do_region_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x3b);
+}
 
 #ifdef CONFIG_PFAULT
 /*
diff -urN linux-2.4.19-pre2/arch/sh/kernel/entry.S linux-2.4.19-pre3/arch/sh/kernel/entry.S
--- linux-2.4.19-pre2/arch/sh/kernel/entry.S	Mon Oct  8 10:39:18 2001
+++ linux-2.4.19-pre3/arch/sh/kernel/entry.S	Mon Mar 11 14:13:27 2002
@@ -1298,6 +1298,8 @@
 	.long SYMBOL_NAME(sys_madvise)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
+	.long SYMBOL_NAME(sys_gettid)
+	.long SYMBOL_NAME(sys_tkill)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
diff -urN linux-2.4.19-pre2/arch/sh/kernel/signal.c linux-2.4.19-pre3/arch/sh/kernel/signal.c
--- linux-2.4.19-pre2/arch/sh/kernel/signal.c	Mon Oct 15 13:36:48 2001
+++ linux-2.4.19-pre3/arch/sh/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -671,10 +671,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/sparc/kernel/signal.c linux-2.4.19-pre3/arch/sparc/kernel/signal.c
--- linux-2.4.19-pre2/arch/sparc/kernel/signal.c	Wed Jan 24 15:18:06 2001
+++ linux-2.4.19-pre3/arch/sparc/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -1279,10 +1279,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/sparc/kernel/systbls.S linux-2.4.19-pre3/arch/sparc/kernel/systbls.S
--- linux-2.4.19-pre2/arch/sparc/kernel/systbls.S	Sun Oct 21 10:36:54 2001
+++ linux-2.4.19-pre3/arch/sparc/kernel/systbls.S	Mon Mar 11 14:13:27 2002
@@ -70,7 +70,7 @@
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_nis_syscall, sys_nis_syscall
+/*255*/	.long sys_nis_syscall, sys_nis_syscall, sys_tkill
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
diff -urN linux-2.4.19-pre2/arch/sparc64/kernel/signal.c linux-2.4.19-pre3/arch/sparc64/kernel/signal.c
--- linux-2.4.19-pre2/arch/sparc64/kernel/signal.c	Sun Mar 25 18:14:21 2001
+++ linux-2.4.19-pre3/arch/sparc64/kernel/signal.c	Mon Mar 11 14:13:27 2002
@@ -806,10 +806,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/sparc64/kernel/signal32.c linux-2.4.19-pre3/arch/sparc64/kernel/signal32.c
--- linux-2.4.19-pre2/arch/sparc64/kernel/signal32.c	Thu Apr 26 22:17:25 2001
+++ linux-2.4.19-pre3/arch/sparc64/kernel/signal32.c	Mon Mar 11 14:13:27 2002
@@ -1478,10 +1478,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -urN linux-2.4.19-pre2/arch/sparc64/kernel/systbls.S linux-2.4.19-pre3/arch/sparc64/kernel/systbls.S
--- linux-2.4.19-pre2/arch/sparc64/kernel/systbls.S	Sun Oct 21 10:36:54 2001
+++ linux-2.4.19-pre3/arch/sparc64/kernel/systbls.S	Mon Mar 11 14:13:27 2002
@@ -70,7 +70,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_tkill
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -129,7 +129,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_tkill
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
diff -urN linux-2.4.19-pre2/drivers/acorn/char/mouse_ps2.c linux-2.4.19-pre3/drivers/acorn/char/mouse_ps2.c
--- linux-2.4.19-pre2/drivers/acorn/char/mouse_ps2.c	Sun Aug 12 10:38:48 2001
+++ linux-2.4.19-pre3/drivers/acorn/char/mouse_ps2.c	Mon Mar 11 14:13:27 2002
@@ -273,7 +273,8 @@
 	iomd_writeb(0, IOMD_MSECTL);
 	iomd_writeb(8, IOMD_MSECTL);
   
-	misc_register(&psaux_mouse);
+	if (misc_register(&psaux_mouse))
+		return -ENODEV;
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
diff -urN linux-2.4.19-pre2/drivers/acorn/scsi/ecoscsi.c linux-2.4.19-pre3/drivers/acorn/scsi/ecoscsi.c
--- linux-2.4.19-pre2/drivers/acorn/scsi/ecoscsi.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre3/drivers/acorn/scsi/ecoscsi.c	Mon Mar 11 14:13:27 2002
@@ -125,7 +125,10 @@
     }
 
     NCR5380_init(instance, 0);
-    request_region (instance->io_port, instance->n_io_port, "ecoscsi");
+    if (request_region (instance->io_port, instance->n_io_port, "ecoscsi") == NULL) {
+	scsi_unregister(instance);
+	return 0;
+    }
 
     if (instance->irq != IRQ_NONE)
 	if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
diff -urN linux-2.4.19-pre2/drivers/atm/fore200e.c linux-2.4.19-pre3/drivers/atm/fore200e.c
--- linux-2.4.19-pre2/drivers/atm/fore200e.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.19-pre3/drivers/atm/fore200e.c	Mon Mar 11 14:13:27 2002
@@ -252,7 +252,7 @@
 fore200e_spin(int msecs)
 {
     unsigned long timeout = jiffies + MSECS(msecs);
-    while (jiffies < timeout);
+    while (time_before(jiffies, timeout));
 }
 
 
@@ -267,7 +267,7 @@
 	if ((ok = (*addr == val)) || (*addr & STATUS_ERROR))
 	    break;
 
-    } while (jiffies < timeout);
+    } while (time_before(jiffies, timeout));
 
 #if 1
     if (!ok) {
@@ -290,7 +290,7 @@
 	if ((ok = (fore200e->bus->read(addr) == val)))
 	    break;
 
-    } while (jiffies < timeout);
+    } while (time_before(jiffies, timeout));
 
 #if 1
     if (!ok) {
@@ -2417,7 +2417,7 @@
     unsigned long      timeout = jiffies + MSECS(50);
     int                c;
 
-    while (jiffies < timeout) {
+    while (time_before(jiffies, timeout)) {
 
 	c = (int) fore200e->bus->read(&monitor->soft_uart.recv);
 
diff -urN linux-2.4.19-pre2/drivers/block/cciss.c linux-2.4.19-pre3/drivers/block/cciss.c
--- linux-2.4.19-pre2/drivers/block/cciss.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/block/cciss.c	Mon Mar 11 14:13:27 2002
@@ -631,6 +631,7 @@
 		char 	*buff = NULL;
 		u64bit	temp64;
 		unsigned long flags;
+		DECLARE_COMPLETION(wait);
 
 		if (!arg) return -EINVAL;
 	
@@ -696,6 +697,8 @@
 			c->SG[0].Len = iocommand.buf_size;
 			c->SG[0].Ext = 0;  // we are not chaining
 		}
+		c->waiting = &wait;
+
 		/* Put the request on the tail of the request queue */
 		spin_lock_irqsave(&io_request_lock, flags);
 		addQ(&h->reqQ, c);
@@ -703,9 +706,7 @@
 		start_io(h);
 		spin_unlock_irqrestore(&io_request_lock, flags);
 
-		/* Wait for completion */
-		while(c->cmd_type != CMD_IOCTL_DONE)
-			schedule_timeout(1);
+		wait_for_completion(&wait);
 
 		/* unlock the buffers from DMA */
 		temp64.val32.lower = c->SG[0].Addr.lower;
@@ -1512,7 +1513,7 @@
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
-					c->cmd_type = CMD_IOCTL_DONE;
+					complete(c->waiting);
 				}
 #				ifdef CONFIG_CISS_SCSI_TAPE
 				else if (c->cmd_type == CMD_SCSI) {
@@ -2126,7 +2127,7 @@
  	/* sendcmd will turn off interrupt, and send the flush...
  	 * To write all data in the battery backed cache to disks */
  	memset(flush_buf, 0, 4);
- 	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4,0,0,0);
+ 	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4,0,0,0, NULL);
  	if (return_code != IO_OK) {
  		printk(KERN_WARNING 
 			"Error Flushing cache on controller %d\n", i);
diff -urN linux-2.4.19-pre2/drivers/block/cciss_cmd.h linux-2.4.19-pre3/drivers/block/cciss_cmd.h
--- linux-2.4.19-pre2/drivers/block/cciss_cmd.h	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/block/cciss_cmd.h	Mon Mar 11 14:13:27 2002
@@ -222,7 +222,6 @@
 /* Command types */
 #define CMD_RWREQ       0x00
 #define CMD_IOCTL_PEND  0x01
-#define CMD_IOCTL_DONE  0x02
 #define CMD_SCSI	0x03
 #define CMD_MSG_DONE	0x04
 #define CMD_MSG_TIMEOUT 0x05
@@ -240,6 +239,7 @@
   struct _CommandList_struct *prev;
   struct _CommandList_struct *next;
   struct request *	   rq;
+  struct completion *waiting;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif
diff -urN linux-2.4.19-pre2/drivers/block/cciss_scsi.c linux-2.4.19-pre3/drivers/block/cciss_scsi.c
--- linux-2.4.19-pre2/drivers/block/cciss_scsi.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/block/cciss_scsi.c	Mon Mar 11 14:13:27 2002
@@ -887,6 +887,7 @@
 			int direction)
 {
 	unsigned long flags;
+	DECLARE_COMPLETION(wait);
 
 	cp->cmd_type = CMD_IOCTL_PEND;		// treat this like an ioctl
 	cp->scsi_cmd = NULL;
@@ -912,6 +913,8 @@
 			(unsigned char *) buf, bufsize,
 			scsi_to_pci_dma_dir(SCSI_DATA_READ));
 
+	cp->waiting = &wait;
+
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&c->reqQ, cp);
@@ -919,9 +922,7 @@
 	start_io(c);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	/* Wait for the request to complete */
-	while(cp->cmd_type != CMD_IOCTL_DONE)
-		schedule_timeout(1);
+	wait_for_completion(&wait);
 
 	/* undo the dma mapping */
 	cciss_unmap_one(c->pdev, cp, bufsize,
@@ -1068,10 +1069,10 @@
 	cdb[3] = 0;
 	cdb[4] = 0;
 	cdb[5] = 0;
-	cdb[6] = (sizeof(*buf) >> 24) & 0xFF;  //MSB
-	cdb[7] = (sizeof(*buf) >> 16) & 0xFF;
-	cdb[8] = (sizeof(*buf) >> 8) & 0xFF;
-	cdb[9] = sizeof(*buf) & 0xFF;
+	cdb[6] = (bufsize >> 24) & 0xFF;  //MSB
+	cdb[7] = (bufsize >> 16) & 0xFF;
+	cdb[8] = (bufsize >> 8) & 0xFF;
+	cdb[9] = bufsize & 0xFF;
 	cdb[10] = 0;
 	cdb[11] = 0;
 
diff -urN linux-2.4.19-pre2/drivers/bluetooth/hci_vhci.c linux-2.4.19-pre3/drivers/bluetooth/hci_vhci.c
--- linux-2.4.19-pre2/drivers/bluetooth/hci_vhci.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/bluetooth/hci_vhci.c	Mon Mar 11 14:13:27 2002
@@ -221,11 +221,6 @@
 	return ret;
 }
 
-static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
 static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	return -EINVAL;
@@ -296,7 +291,7 @@
 
 static struct file_operations hci_vhci_fops = {
 	owner:	THIS_MODULE,	
-	llseek:	hci_vhci_chr_lseek,
+	llseek:	no_llseek,
 	read:	hci_vhci_chr_read,
 	write:	hci_vhci_chr_write,
 	poll:	hci_vhci_chr_poll,
diff -urN linux-2.4.19-pre2/drivers/char/Config.in linux-2.4.19-pre3/drivers/char/Config.in
--- linux-2.4.19-pre2/drivers/char/Config.in	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/char/Config.in	Mon Mar 11 14:13:27 2002
@@ -62,27 +62,29 @@
      tristate '    Stallion EasyIO or EC8/32 support' CONFIG_STALLION
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
-   bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
-   dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
-   bool '  Enable Au1000 UART Support' CONFIG_AU1000_UART
-   if [ "$CONFIG_AU1000_UART" = "y" ]; then
-      bool '        Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE
-   fi
-   bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL 
-   if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then
-      bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE  
-   fi                             
-   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
-      bool '  Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART
-      if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then
-	 bool '  Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE
-	 if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then
-	    define_bool CONFIG_SERIAL_CONSOLE y
-	 fi
-	 int  '  Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024
-	 bool '  Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1
-      fi
-   fi
+   if [ "CONFIG_MIPS" = "y" ]; then
+     bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
+     dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
+     bool '  Enable Au1000 UART Support' CONFIG_AU1000_UART
+     if [ "$CONFIG_AU1000_UART" = "y" ]; then
+        bool '        Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE
+     fi
+     bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL 
+     if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then
+        bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE  
+     fi                             
+     if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+        bool '  Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART
+        if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then
+           bool '  Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE
+	   if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then
+	      define_bool CONFIG_SERIAL_CONSOLE y
+	   fi
+	   int  '  Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024
+	   bool '  Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1
+       fi
+     fi
+  fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
    tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
@@ -239,7 +241,7 @@
 
 dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
 if [ "$CONFIG_AGP" != "n" ]; then
-   bool '  Intel 440LX/BX/GX and I815/I830M/I840/I850 support' CONFIG_AGP_INTEL
+   bool '  Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
    bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
    bool '  VIA chipset support' CONFIG_AGP_VIA
    bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
diff -urN linux-2.4.19-pre2/drivers/char/acquirewdt.c linux-2.4.19-pre3/drivers/char/acquirewdt.c
--- linux-2.4.19-pre2/drivers/char/acquirewdt.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.19-pre3/drivers/char/acquirewdt.c	Mon Mar 11 14:13:27 2002
@@ -209,7 +209,8 @@
 	printk("WDT driver for Acquire single board computer initialising.\n");
 
 	spin_lock_init(&acq_lock);
-	misc_register(&acq_miscdev);
+	if (misc_register(&acq_miscdev))
+		return -ENODEV;
 	request_region(WDT_STOP, 1, "Acquire WDT");
 	request_region(WDT_START, 1, "Acquire WDT");
 	register_reboot_notifier(&acq_notifier);
diff -urN linux-2.4.19-pre2/drivers/char/esp.c linux-2.4.19-pre3/drivers/char/esp.c
--- linux-2.4.19-pre2/drivers/char/esp.c	Fri Nov  9 14:01:21 2001
+++ linux-2.4.19-pre3/drivers/char/esp.c	Mon Mar 11 14:13:27 2002
@@ -2162,7 +2162,7 @@
 		if (signal_pending(current))
 			break;
 
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 
 		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
diff -urN linux-2.4.19-pre2/drivers/char/pc_keyb.c linux-2.4.19-pre3/drivers/char/pc_keyb.c
--- linux-2.4.19-pre2/drivers/char/pc_keyb.c	Fri Nov  9 14:01:21 2001
+++ linux-2.4.19-pre3/drivers/char/pc_keyb.c	Mon Mar 11 14:13:27 2002
@@ -1215,3 +1215,26 @@
 }
 
 #endif /* CONFIG_PSMOUSE */
+
+
+/* Tell the user who may be running in X and not see the console that we have 
+   panic'ed. This is to distingush panics from "real" lockups. 
+   Could in theory send the panic message as morse, but that is left as an
+   exercise for the reader.  */ 
+void panic_blink(void)
+{ 
+	static unsigned long last_jiffie;
+	static char led;
+	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is 
+	   different. */
+	if (jiffies - last_jiffie > HZ/2) {
+		led ^= 0x01 | 0x04;
+		while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); 
+		kbd_write_output(KBD_CMD_SET_LEDS);
+		mdelay(1); 
+		while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); 
+		mdelay(1); 
+		kbd_write_output(led);
+		last_jiffie = jiffies;
+	}
+}  
diff -urN linux-2.4.19-pre2/drivers/char/serial_txx927.c linux-2.4.19-pre3/drivers/char/serial_txx927.c
--- linux-2.4.19-pre2/drivers/char/serial_txx927.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/char/serial_txx927.c	Mon Mar 11 14:13:28 2002
@@ -78,7 +78,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/serialP.h>
 #include <linux/delay.h>
diff -urN linux-2.4.19-pre2/drivers/i2c/i2c-algo-bit.c linux-2.4.19-pre3/drivers/i2c/i2c-algo-bit.c
--- linux-2.4.19-pre2/drivers/i2c/i2c-algo-bit.c	Thu Oct 11 08:05:47 2001
+++ linux-2.4.19-pre3/drivers/i2c/i2c-algo-bit.c	Mon Mar 11 14:13:28 2002
@@ -49,7 +49,7 @@
 /* respectively. This makes sure that the algorithm works. Some chips   */
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
-#define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+#define SLO_IO      jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
                         if (need_resched) schedule();
 */
 
@@ -117,7 +117,7 @@
  		 * while they are processing data internally. 
  		 */
 		setscl(adap,1);
-		if (start+adap->timeout <= jiffies) {
+		if (time_after_eq(jiffies, start+adap->timeout)) {
 			return -ETIMEDOUT;
 		}
 		if (current->need_resched)
diff -urN linux-2.4.19-pre2/drivers/ide/Config.in linux-2.4.19-pre3/drivers/ide/Config.in
--- linux-2.4.19-pre2/drivers/ide/Config.in	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/Config.in	Mon Mar 11 14:13:28 2002
@@ -14,6 +14,7 @@
 
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+   dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
    define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
    dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
@@ -32,6 +33,9 @@
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
+   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+#   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
+
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
       dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
@@ -43,14 +47,17 @@
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-#	    bool '    Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
-	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+	    dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+            dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-#	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+#	    dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
+	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
 
 	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
@@ -59,6 +66,7 @@
 	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
 	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
   	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
@@ -72,24 +80,19 @@
 	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
 	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	    fi
-	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
-	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
-	    fi
-	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
 	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
+	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
 	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
 	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
 	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
          fi
 
-#	 dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
-
 	 if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
 	    bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
 	 fi
@@ -156,6 +159,8 @@
 	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       fi
    fi
+
+   bool '  Use the NOOP Elevator (WARNING)' CONFIG_BLK_DEV_ELEVATOR_NOOP
 else
    bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
    define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_ONLY
@@ -180,6 +185,7 @@
 else
   define_bool CONFIG_DMA_NONPCI n
 fi
+
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
diff -urN linux-2.4.19-pre2/drivers/ide/Makefile linux-2.4.19-pre3/drivers/ide/Makefile
--- linux-2.4.19-pre2/drivers/ide/Makefile	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/Makefile	Mon Mar 11 14:13:28 2002
@@ -10,7 +10,7 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ataraid.o
+export-objs		:= ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o
 list-multi		:= ide-mod.o ide-probe-mod.o
 
 obj-y		:=
@@ -24,6 +24,7 @@
 obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
+
 obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
 
 ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
@@ -70,13 +71,13 @@
 
 # The virtualised raid layers MUST come after the ide itself or bad stuff
 # will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)	+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
 
 ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
 
-ide-mod-objs		:= ide.o ide-features.o $(ide-obj-y)
+ide-mod-objs		:= ide.o ide-features.o ide-taskfile.o $(ide-obj-y)
 ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre2/drivers/ide/alim15x3.c linux-2.4.19-pre3/drivers/ide/alim15x3.c
--- linux-2.4.19-pre2/drivers/ide/alim15x3.c	Sun Jul 15 16:22:23 2001
+++ linux-2.4.19-pre3/drivers/ide/alim15x3.c	Mon Mar 11 14:13:28 2002
@@ -453,7 +453,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
 				if ((id->field_valid & 2) &&
diff -urN linux-2.4.19-pre2/drivers/ide/amd74xx.c linux-2.4.19-pre3/drivers/ide/amd74xx.c
--- linux-2.4.19-pre2/drivers/ide/amd74xx.c	Mon Aug 13 14:56:19 2001
+++ linux-2.4.19-pre3/drivers/ide/amd74xx.c	Mon Mar 11 14:13:28 2002
@@ -75,7 +75,8 @@
 {
 	unsigned int class_rev;
 
-	if (dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
+	if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) ||
+	    (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441))
 		return 0;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
@@ -122,8 +123,8 @@
 	pci_read_config_byte(dev, 0x4c, &pio_timing);
 
 #ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
+	printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
+		drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing);
 #endif
 
 	ultra_timing	&= ~0xC7;
@@ -131,22 +132,19 @@
 	pio_timing	&= ~(0x03 << drive->dn);
 
 #ifdef DEBUG
-	printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		ultra_timing, dma_pio_timing, pio_timing);
+	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
+		drive->name, ultra_timing, dma_pio_timing, pio_timing);
 #endif
 
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
 		case XFER_UDMA_5:
-#undef __CAN_MODE_5
-#ifdef __CAN_MODE_5
 			ultra_timing |= 0x46;
 			dma_pio_timing |= 0x20;
 			break;
-#else
-			printk("%s: setting to mode 4, driver problems in mode 5.\n", drive->name);
-			speed = XFER_UDMA_4;
-#endif /* __CAN_MODE_5 */
 		case XFER_UDMA_4:
 			ultra_timing |= 0x45;
 			dma_pio_timing |= 0x20;
@@ -164,7 +162,7 @@
 			dma_pio_timing |= 0x20;
 			break;
 		case XFER_UDMA_0:
-			ultra_timing |= 0x42;
+		ultra_timing |= 0x42;
 			dma_pio_timing |= 0x20;
 			break;
 		case XFER_MW_DMA_2:
@@ -222,8 +220,8 @@
 	pci_write_config_byte(dev, 0x4c, pio_timing);
 
 #ifdef DEBUG
-	printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		ultra_timing, dma_pio_timing, pio_timing);
+	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
+		drive->name, ultra_timing, dma_pio_timing, pio_timing);
 #endif
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -303,11 +301,15 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	struct hd_driveid *id	= drive->id;
 	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= (dev->device==PCI_DEVICE_ID_AMD_VIPER_7411) ? 1 : 0;
+	byte udma_100		= ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)||
+				   (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0;
 	byte speed		= 0x00;
 	int  rval;
 
-	if ((id->dma_ultra & 0x0020) && (udma_66)&& (udma_100)) {
+	if (udma_100)
+		udma_66 = eighty_ninty_three(drive);
+
+	if ((id->dma_ultra & 0x0020) && (udma_66) && (udma_100)) {
 		speed = XFER_UDMA_5;
 	} else if ((id->dma_ultra & 0x0010) && (udma_66)) {
 		speed = XFER_UDMA_4;
@@ -331,7 +333,7 @@
 
 	(void) amd74xx_tune_chipset(drive, speed);
 
-	rval = (int)(	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
 			((id->dma_mword >> 8) & 7) ? ide_dma_on :
 						     ide_dma_off_quietly);
@@ -352,7 +354,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) &&
@@ -442,17 +444,43 @@
 
 unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
 {
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte cable_80_pin[2]	= { 0, 0 };
+	byte ata66		= 0;
+	byte tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x42, &tmpbyte);
+
+	/*
+	 * 0x42, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x42, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
 #ifdef CONFIG_AMD74XX_OVERRIDE
-	byte ata66 = 1;
+	return(1);
 #else
-	byte ata66 = 0;
+	return (unsigned int) ata66;
 #endif /* CONFIG_AMD74XX_OVERRIDE */
-
-#if 0
-	pci_read_config_byte(hwif->pci_dev, 0x48, &ata66);
-	return ((ata66 & 0x02) ? 0 : 1);
-#endif
-	return ata66;
 }
 
 void __init ide_init_amd74xx (ide_hwif_t *hwif)
diff -urN linux-2.4.19-pre2/drivers/ide/cmd64x.c linux-2.4.19-pre3/drivers/ide/cmd64x.c
--- linux-2.4.19-pre2/drivers/ide/cmd64x.c	Thu Jul 27 16:40:57 2000
+++ linux-2.4.19-pre3/drivers/ide/cmd64x.c	Mon Mar 11 14:13:28 2002
@@ -86,6 +86,7 @@
 #include <linux/proc_fs.h>
 
 static int cmd64x_get_info(char *, char **, off_t, int);
+static int cmd680_get_info(char *, char **, off_t, int);
 extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
@@ -180,24 +181,21 @@
 	return p-buffer;	/* => must be less than 4k! */
 }
 
-#if 0
-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-	p += sprintf(p, "thingy stuff\n");
-	return (char *)p;
-}
-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = cmd64x_chipset_data(buffer, bmide_dev);
-	return p-buffer;	/* hoping it is less than 4K... */
+	p += sprintf(p, "\n                                CMD680 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
+		"?", "?", "?", "?");
+	return p-buffer;	/* => must be less than 4k! */
 }
-#endif
 
 #endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
 byte cmd64x_proc = 0;
+byte cmd680_proc = 0;
 
 /*
  * Registers and masks for easy access by drive index:
@@ -345,10 +343,58 @@
 		setup_count, active_count, recovery_count);
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
 {
-	byte speed= 0x00;
-	byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
+	unsigned short		timing;
+
+	pci_read_config_word(dev, addr_mask, &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte			drive_pci;
+	unsigned short		speedt;
+
+	switch (drive->dn) {
+		case 0: drive_pci = 0xA4; break;
+		case 1: drive_pci = 0xA6; break;
+		case 2: drive_pci = 0xB4; break;
+		case 3: drive_pci = 0xB6; break;
+		default: return;
+        }
+
+	pci_read_config_word(dev, drive_pci, &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(cmd680_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	byte speed	= 0x00;
+	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
 
 	cmd64x_tuneproc(drive, set_pio);
 	speed = XFER_PIO_0 + set_pio;
@@ -356,6 +402,41 @@
 		(void) ide_config_drive_speed(drive, speed);
 }
 
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 speed		= 0x00;
+	u8 mode_pci		= 0x00;
+	u8 channel_timings	= cmd680_taskfile_timing(hwif);
+	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	cmd680_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed) {
+		(void) ide_config_drive_speed(drive, speed);
+		drive->current_speed = speed;
+	}
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+		config_cmd680_chipset_for_pio(drive, set_speed);
+	} else {
+		config_cmd64x_chipset_for_pio(drive, set_speed);
+	}
+}
+
 static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -363,7 +444,7 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	int err			= 0;
 
-	byte unit		= (drive->select.b.unit & 0x01);
+	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
 	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
 	u8 regU			= 0;
@@ -424,8 +505,123 @@
 	return err;
 }
 
+static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_pci		= 0;
+	u8 udma_pci		= 0;
+	u8 mode_pci		= 0;
+	u8 scsc			= 0;
+	u16 ultra		= 0;
+	u16 multi		= 0;
+	int err			= 0;
+
+        pci_read_config_byte(dev, addr_mask, &mode_pci);
+	pci_read_config_byte(dev, 0x8A, &scsc);
+
+        switch (drive->dn) {
+		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
+		default: return 1;
+	}
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+	pci_read_config_word(dev, dma_pci, &multi);
+	pci_read_config_word(dev, udma_pci, &ultra);
+
+	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
+		pci_write_config_byte(dev, 0x8A, scsc|0x01);
+		pci_read_config_byte(dev, 0x8A, &scsc);
+	}
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:
+			if ((scsc & 0x30) == 0x00)
+				goto speed_break;
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= 0x01;
+			break;
+speed_break :
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
+			break;
+		case XFER_UDMA_4:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
+			break;
+		case XFER_UDMA_3:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
+			break;
+		case XFER_UDMA_2:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
+			break;
+		case XFER_UDMA_1:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
+			break;
+		case XFER_UDMA_0:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
+			break;
+		case XFER_MW_DMA_2:
+			multi = 0x10C1;
+			break;
+		case XFER_MW_DMA_1:
+			multi = 0x10C2;
+			break;
+		case XFER_MW_DMA_0:
+			multi = 0x2208;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
+		default:
+			return 1;
+	}
+
+	
+	if (speed >= XFER_MW_DMA_0) 
+		config_cmd680_chipset_for_pio(drive, 0);
+
+	if (speed >= XFER_UDMA_0)
+		mode_pci |= ((unit) ? 0x30 : 0x03);
+	else if (speed >= XFER_MW_DMA_0)
+		mode_pci |= ((unit) ? 0x20 : 0x02);
+	else
+		mode_pci |= ((unit) ? 0x10 : 0x01);
+
+	pci_write_config_byte(dev, addr_mask, mode_pci);
+	pci_write_config_word(dev, dma_pci, multi);
+	pci_write_config_word(dev, udma_pci, ultra);
+
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+	return err;
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -510,6 +706,55 @@
 	return rval;
 }
 
+static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte udma_66		= eighty_ninty_three(drive);
+	byte speed		= 0x00;
+	byte set_pio		= 0x00;
+	int rval;
+
+	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020) && (udma_66))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
+	else if (id->dma_ultra & 0x0004)		speed = XFER_UDMA_2;
+	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
+	else if (id->dma_ultra & 0x0001)		speed = XFER_UDMA_0;
+	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
+	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
+	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
+	else {
+		set_pio = 1;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	config_chipset_for_pio(drive, set_pio);
+
+	if (set_pio)
+		return ((int) ide_dma_off_quietly);
+
+	if (cmd680_tune_chipset(drive, speed))
+		return ((int) ide_dma_off);
+
+	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+	return rval;
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+		return (config_cmd680_chipset_for_dma(drive));
+	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
+}
+
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
@@ -519,12 +764,15 @@
 	byte can_ultra_33	= 0;
 	byte can_ultra_66	= 0;
 	byte can_ultra_100	= 0;
+	byte can_ultra_133	= 0;
 	ide_dma_action_t dma_func = ide_dma_on;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;	
 
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			can_ultra_133 = 1;
 		case PCI_DEVICE_ID_CMD_649:
 			can_ultra_100 = 1;
 		case PCI_DEVICE_ID_CMD_648:
@@ -550,7 +798,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
 				if ((id->field_valid & 2) &&
@@ -586,6 +834,18 @@
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		default:
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+        return ide_dmaproc(func, drive);
+}
+
 static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	byte dma_stat		= 0;
@@ -663,7 +923,78 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+static int cmd680_busproc (ide_drive_t * drive, int state)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	u32 stat_config		= 0;
+
+        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
+
+	if (!hwif)
+		return -EINVAL;
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+#endif
+	return 0;
+}
+
+void cmd680_reset (ide_drive_t *drive)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	byte reset		= 0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
+#endif
+}
+
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+{
+	u8 tmpbyte	= 0;	
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x328A);
+	pci_write_config_dword(dev, 0xA8, 0x4392);
+	pci_write_config_dword(dev, 0xAC, 0x4009);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x328A);
+	pci_write_config_dword(dev, 0xB8, 0x4392);
+	pci_write_config_dword(dev, 0xBC, 0x4009);
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		bmide_dev = dev;
+		cmd64x_display_info = &cmd680_get_info;
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
 {
 	unsigned char mrdmode;
 	unsigned int class_rev;
@@ -752,7 +1083,23 @@
 	return 0;
 }
 
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_pci_init (dev, name);
+	return cmd64x_pci_init (dev, name);
+}
+
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+{
+	byte ata66	= 0;
+	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
+	return (ata66 & 0x01) ? 1 : 0;
+}
+
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
 {
 	byte ata66 = 0;
 	byte mask = (hwif->channel) ? 0x02 : 0x01;
@@ -761,6 +1108,14 @@
 	return (ata66 & mask) ? 1 : 0;
 }
 
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_ata66(hwif);
+	return cmd64x_ata66(hwif);
+}
+
 void __init ide_init_cmd64x (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -769,8 +1124,6 @@
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
-	hwif->tuneproc	= &cmd64x_tuneproc;
-	hwif->speedproc	= &cmd64x_tune_chipset;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 
@@ -779,10 +1132,19 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			hwif->busproc	= &cmd680_busproc;
+			hwif->dmaproc	= &cmd680_dmaproc;
+			hwif->resetproc = &cmd680_reset;
+			hwif->speedproc	= &cmd680_tune_chipset;
+			hwif->tuneproc	= &cmd680_tuneproc;
+			break;
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc = &cmd64x_dmaproc;
+			hwif->dmaproc	= &cmd64x_dmaproc;
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc = &cmd64x_tune_chipset;
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
@@ -791,6 +1153,8 @@
 			} else {
 				hwif->dmaproc = &cmd64x_dmaproc;
 			}
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc	= &cmd64x_tune_chipset;
 			break;
 		default:
 			break;
diff -urN linux-2.4.19-pre2/drivers/ide/hpt366.c linux-2.4.19-pre3/drivers/ide/hpt366.c
--- linux-2.4.19-pre2/drivers/ide/hpt366.c	Tue Aug 14 20:01:07 2001
+++ linux-2.4.19-pre3/drivers/ide/hpt366.c	Mon Mar 11 14:13:28 2002
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/ide/hpt366.c		Version 0.18	June. 9, 2000
+ * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
  *
  * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
  *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
  */
 
 #include <linux/config.h>
@@ -28,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -35,6 +65,11 @@
 
 #define DISPLAY_HPT366_TIMINGS
 
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -106,146 +141,302 @@
 
 struct chipset_bus_clock_list_entry {
 	byte		xfer_speed;
-	unsigned int	chipset_settings_write;
-	unsigned int	chipset_settings_read;
+	unsigned int	chipset_settings;
 };
 
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
 struct chipset_bus_clock_list_entry forty_base [] = {
 
-	{	XFER_UDMA_4,	0x900fd943,	0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9,	0xc018d9d9	},
-	{	0,		0x0120d9d9,	0x0120d9d9	}
+	{	XFER_UDMA_4,    0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
 };
 
 struct chipset_bus_clock_list_entry thirty_three_base [] = {
 
-	{	XFER_UDMA_4,	0x90c9a731,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7,	0x0120a7a7	}
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
 };
 
 struct chipset_bus_clock_list_entry twenty_five_base [] = {
 
-	{	XFER_UDMA_4,	0x90c98521,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585,	0xc0d08585	},
-	{	0,		0x01208585,	0x01208585	}
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
 };
 
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
 struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57,	0x06914e57	},
-	{	0,		0x06514e57,	0x06514e57	}
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
+};
+
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+#else
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;
 
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	char *p		= buffer;
-	u32 bibma	= bmide_dev->resource[4].start;
-	u32 bibma2 	= bmide2_dev->resource[4].start;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
-	u8  c0 = 0, c1 = 0;
-	u32 class_rev;
-
-	pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	if (bmide2_dev)
-		c1 = inb_p((unsigned short)bibma2 + 0x02);
-
-	p += sprintf(p, "\n                                %s Chipset.\n", chipset_names[class_rev]);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev;
+		u8 c0, c1;
+
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+		class_rev &= 0xff;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb_p(iobase + 0x2);
+		c1 = inb_p(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (pci_rev_check_hpt3xx(dev)) {
+			u8 cbl;
+			cbl = inb_p(iobase + 0x7b);
+			outb_p(cbl | 1, iobase + 0x7b);
+			outb_p(cbl & ~1, iobase + 0x7b);
+			cbl = inb_p(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
 
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
 	return p-buffer;/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
 	unsigned int class_rev;
@@ -282,16 +473,16 @@
 	return 0;
 }
 
-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+			return chipset_table->chipset_settings;
 		}
-	return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+	return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,7 +495,7 @@
 	byte drive_fast		= 0;
 
 	/*
-	 * Disable the "fast interrupt" prediction.
+	 * Disable the "fast interrupt" prediction. 
 	 */
 	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
 	if (drive_fast & 0x02)
@@ -314,16 +505,22 @@
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
-			reg2 = pci_bus_clock_list(speed, direction, forty_base);
+			reg2 = pci_bus_clock_list(speed, forty_base);
 			break;
 		case 9:
-			reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+			reg2 = pci_bus_clock_list(speed, twenty_five_base);
 			break;
 		default:
 		case 7:
-			reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+			reg2 = pci_bus_clock_list(speed, thirty_three_base);
 			break;
 	}
+#if 0
+	/* this is a nice idea ... */
+	list_conf = pci_bus_clock_list(speed,
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
+#endif
 	/*
 	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
 	 */
@@ -337,40 +534,47 @@
 	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	byte reg5bh		= (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
-	unsigned int list_conf	= pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+	unsigned int list_conf	= 0;
 	unsigned int drive_conf = 0;
 	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0;
-	byte drive_fast		= 0;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte new_fast, drive_fast		= 0;
+	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
 
-	switch (drive->dn) {
-		case 0: drive_pci = 0x40; break;
-		case 1: drive_pci = 0x44; break;
-		case 2: drive_pci = 0x48; break;
-		case 3: drive_pci = 0x4c; break;
-		default: return;
-	}
 	/*
 	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
 	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
 
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	list_conf &= ~0x80000000;
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
 
-	pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -382,9 +586,9 @@
 		drive->init_speed = speed;
 
 	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed, 0);
+		hpt370_tune_chipset(drive, speed);
         } else {
-                hpt366_tune_chipset(drive, speed, 0);
+                hpt366_tune_chipset(drive, speed);
         }
 	drive->current_speed = speed;
 	return ((int) ide_config_drive_speed(drive, speed));
@@ -541,13 +745,6 @@
 	}
 }
 
-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
-	if ((func != ide_dma_write) || (func != ide_dma_read))
-		return;
-	hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -624,6 +821,13 @@
 				reg50h, reg52h, reg5ah);
 			if (reg5ah & 0x10)
 				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+			/* fall through to a reset */
+#if 0
+		case ide_dma_begin:
+		case ide_dma_end:
+			/* reset the chips state over and over.. */
+			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+#endif
 			break;
 		case ide_dma_timeout:
 		default:
@@ -634,9 +838,52 @@
 
 int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte regstate = hwif->channel ? 0x54 : 0x50;
+	byte reginfo = hwif->channel ? 0x56 : 0x52;
+	byte dma_stat;
+
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = inb(dma_base+2);
+			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+
+		case ide_dma_end:
+			dma_stat = inb(dma_base + 2);
+			if (dma_stat & 0x01) {
+				udelay(20); /* wait a little */
+				dma_stat = inb(dma_base + 2);
+			}
+			if ((dma_stat & 0x01) == 0) 
+				break;
+
+			func = ide_dma_timeout;
+			/* fallthrough */
+
+		case ide_dma_timeout:
+		case ide_dma_lostirq:
+			pci_read_config_byte(hwif->pci_dev, reginfo, 
+					     &dma_stat); 
+			printk("%s: %d bytes in FIFO\n", drive->name, 
+			       dma_stat);
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			dma_stat = inb(dma_base);
+			outb(dma_stat & ~0x1, dma_base); /* stop dma */
+			dma_stat = inb(dma_base + 2); 
+			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+			/* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+	        case ide_dma_begin:
+#endif
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			break;
+
 		default:
 			break;
 	}
@@ -644,6 +891,210 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	byte reg59h		= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte reset		= (hwif->channel) ? 0x80 : 0x40;
+	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
+	byte reg59h		= 0;
+	byte regXXh		= 0;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte tristate, resetmask, bus_reg;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static void __init init_hpt370(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	byte reg5bh;
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		dev->sysdata = (void *) thirty_three_base_hpt370;
+		printk("HPT370: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		dev->sysdata = (void *) fifty_base_hpt370;
+		printk("HPT370: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		dev->sysdata = (void *) sixty_six_base_hpt370;
+		printk("HPT370: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (dev->sysdata) 
+		goto init_hpt370_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				dev->sysdata = (void *) fifty_base_hpt370;
+				printk("HPT370: using 50MHz internal PLL\n");
+				goto init_hpt370_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt370_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+}
+
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
 	byte test = 0;
@@ -652,14 +1103,8 @@
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
 	if (test != (L1_CACHE_BYTES / 4))
 		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif
 
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
 	if (test != 0x78)
@@ -673,17 +1118,18 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
+	if (pci_rev_check_hpt3xx(dev)) {
+		init_hpt370(dev);
+		hpt_devs[n_hpt_devs++] = dev;
+	} else {
+		hpt_devs[n_hpt_devs++] = dev;
+	}
+	
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
 		hpt366_proc = 1;
-		bmide_dev = dev;
-		if (pci_rev_check_hpt3xx(dev))
-			bmide2_dev = dev;
 		hpt366_display_info = &hpt366_get_info;
 	}
-	if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
-		bmide2_dev = dev;
-	}
 #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
 
 	return dev->irq;
@@ -691,38 +1137,58 @@
 
 unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 {
-	byte ata66 = 0;
+	byte ata66	= 0;
+	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
 
 	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & 0x02) ? "33" : "66",
+		ata66, (ata66 & regmask) ? "33" : "66",
 		PCI_FUNC(hwif->pci_dev->devfn));
 #endif /* DEBUG */
-	return ((ata66 & 0x02) ? 0 : 1);
+	return ((ata66 & regmask) ? 0 : 1);
 }
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+	int hpt_rev;
+
 	hwif->tuneproc	= &hpt3xx_tune_drive;
 	hwif->speedproc	= &hpt3xx_tune_chipset;
 	hwif->quirkproc	= &hpt3xx_quirkproc;
 	hwif->intrproc	= &hpt3xx_intrproc;
 	hwif->maskproc	= &hpt3xx_maskproc;
 
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+	if (hpt_rev) {
+		/* set up ioctl for power status. note: power affects both
+		 * drives on each channel */
+		hwif->busproc   = &hpt370_busproc;
+	}
+
 	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
 		/* do nothing now but will split device types */
+		hwif->resetproc = &hpt3xx_reset;
+/*
+ * don't do until we can parse out the cobalt box argh ...
+ *		hwif->busproc   = &hpt3xx_tristate;
+ */
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+		if (hpt_rev) {
 			byte reg5ah = 0;
 			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
 				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
 			hwif->dmaproc = &hpt370_dmaproc;
-			hwif->rwproc = &hpt370_rw_proc;
 		} else {
 			hwif->dmaproc = &hpt366_dmaproc;
 		}
diff -urN linux-2.4.19-pre2/drivers/ide/ide-cd.c linux-2.4.19-pre3/drivers/ide/ide-cd.c
--- linux-2.4.19-pre2/drivers/ide/ide-cd.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre3/drivers/ide/ide-cd.c	Mon Mar 11 14:13:28 2002
@@ -2961,11 +2961,7 @@
 	return 0;
 }
 
-static
-int ide_cdrom_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int ide_cdrom_reinit (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
@@ -2975,6 +2971,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
 	end_request:		NULL,
 	ioctl:			ide_cdrom_ioctl,
@@ -2986,7 +2984,9 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	driver_reinit:		ide_cdrom_reinit,
+	reinit:			ide_cdrom_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
 };
 
 int ide_cdrom_init(void);
@@ -3003,6 +3003,39 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
+int ide_cdrom_reinit (ide_drive_t *drive)
+{
+	struct cdrom_info *info;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+	if (info == NULL) {
+		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		return 1;
+	}
+	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+		kfree (info);
+		return 1;
+	}
+	memset (info, 0, sizeof (struct cdrom_info));
+	drive->driver_data = info;
+	DRIVER(drive)->busy++;
+	if (ide_cdrom_setup (drive)) {
+		DRIVER(drive)->busy--;
+		if (ide_cdrom_cleanup (drive))
+			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 static void __exit ide_cdrom_exit(void)
 {
 	ide_drive_t *drive;
diff -urN linux-2.4.19-pre2/drivers/ide/ide-cd.h linux-2.4.19-pre3/drivers/ide/ide-cd.h
--- linux-2.4.19-pre2/drivers/ide/ide-cd.h	Thu Nov 22 11:46:58 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-cd.h	Mon Mar 11 14:13:28 2002
@@ -38,7 +38,9 @@
 /************************************************************************/
 
 #define SECTOR_BITS 		9
+#ifndef SECTOR_SIZE
 #define SECTOR_SIZE		(1 << SECTOR_BITS)
+#endif
 #define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
 #define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE >> SECTOR_BITS)
diff -urN linux-2.4.19-pre2/drivers/ide/ide-cs.c linux-2.4.19-pre3/drivers/ide/ide-cs.c
--- linux-2.4.19-pre2/drivers/ide/ide-cs.c	Sun Sep 30 12:26:05 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-cs.c	Mon Mar 11 14:13:28 2002
@@ -42,6 +42,7 @@
 #include <linux/ioport.h>
 #include <linux/hdreg.h>
 #include <linux/major.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -226,6 +227,15 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
+int idecs_register (int arg1, int arg2, int irq)
+{
+        hw_regs_t hw;
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+        hw.irq = irq;
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
+        return ide_register_hw(&hw, NULL);
+}
+
 void ide_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -329,10 +339,14 @@
 
     /* retry registration in case device is still spinning up */
     for (i = 0; i < 10; i++) {
-	hd = ide_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
-	    hd = ide_register(io_base+0x10, ctl_base+0x10,
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
+	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
 			      link->irq.AssignedIRQ);
 	    if (hd >= 0) {
 		io_base += 0x10; ctl_base += 0x10;
diff -urN linux-2.4.19-pre2/drivers/ide/ide-disk.c linux-2.4.19-pre3/drivers/ide/ide-disk.c
--- linux-2.4.19-pre2/drivers/ide/ide-disk.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-disk.c	Mon Mar 11 14:13:28 2002
@@ -27,9 +27,11 @@
  * Version 1.09		added increment of rq->sector in ide_multwrite
  *			added UDMA 3/4 reporting
  * Version 1.10		request queue changes, Ultra DMA 100
+ * Version 1.11		added 48-bit lba
+ * Version 1.12		adding taskfile io access method
  */
 
-#define IDEDISK_VERSION	"1.10"
+#define IDEDISK_VERSION	"1.12"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -59,6 +61,14 @@
 #define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
 
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  undef __TASKFILE__IO /* define __TASKFILE__IO */
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifndef __TASKFILE__IO
+
 static void idedisk_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -86,6 +96,8 @@
 		ide_output_data(drive, buffer, wcount);
 }
 
+#endif /* __TASKFILE__IO */
+
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -99,6 +111,11 @@
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+		printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+		return 1;
+	}
+
 	/*
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
@@ -131,6 +148,8 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
+#ifndef __TASKFILE__IO
+
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
@@ -313,53 +332,218 @@
 	}
 	return ide_error(drive, "multwrite_intr", stat);
 }
+#endif /* __TASKFILE__IO */
+
+#ifdef __TASKFILE__IO
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
  */
-static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat;
+	if (rq->cmd == READ)
+		goto good_command;
+	if (rq->cmd == WRITE)
+		goto good_command;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
-		drive->mult_count = drive->mult_req;
-	} else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
-	}
+	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+	ide_end_request(0, HWGROUP(drive));
 	return ide_stopped;
+
+good_command:
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+		return promise_rw_disk(drive, rq, block);
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))	/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
+
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
 }
 
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
 {
-	byte stat;
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
-		return ide_stopped;
+#if 1
+	lba48bit = drive->addressing;
+#endif
 
-	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+
+	task_ioreg_t command	= get_command(drive, rq->cmd);
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+	taskfile.sector_number	= sect;
+	taskfile.low_cylinder	= cyl;
+	taskfile.high_cylinder	= (cyl>>8);
+	taskfile.device_head	= head;
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+
+	task_ioreg_t command	= get_command(drive, rq->cmd);
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f);
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
+
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
-	return ide_started;	
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
 }
 
 /*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
  */
-static ide_startstop_t recal_intr (ide_drive_t *drive)
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
 {
-	byte stat = GET_STAT();
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+
+	task_ioreg_t command	= get_command(drive, rq->cmd);
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	taskfile.sector_count	= rq->nr_sectors;
+	hobfile.sector_count	= (rq->nr_sectors>>8);
+
+	if (rq->nr_sectors == 65536) {
+		taskfile.sector_count	= 0x00;
+		hobfile.sector_count	= 0x00;
+	}
+
+	taskfile.sector_number	= block;	/* low lba */
+	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
+	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	hobfile.sector_number	= (block>>=8);	/* low lba */
+	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
+	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	taskfile.device_head	= drive->select.all;
+	hobfile.device_head	= taskfile.device_head;
+	hobfile.control		= (drive->ctl|0x80);
+	taskfile.command	= command;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
-	return ide_stopped;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
 }
 
+#else /* !__TASKFILE__IO */
 /*
  * do_rw_disk() issues READ and WRITE commands to a disk,
  * using LBA if supported, or CHS otherwise, to address sectors.
@@ -369,22 +553,70 @@
 {
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE(0x00, IDE_FEATURE_REG);
-	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
+
 #ifdef CONFIG_BLK_DEV_PDC4030
 	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
 #else /* !CONFIG_BLK_DEV_PDC4030 */
 	if (drive->select.b.lba) {
 #endif /* CONFIG_BLK_DEV_PDC4030 */
+
+		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+			task_ioreg_t tasklets[10];
+
+			tasklets[0] = 0;
+			tasklets[1] = 0;
+			tasklets[2] = rq->nr_sectors;
+			tasklets[3] = (rq->nr_sectors>>8);
+			if (rq->nr_sectors == 65536) {
+				tasklets[2] = 0x00;
+				tasklets[3] = 0x00;
+			}
+			tasklets[4] = (task_ioreg_t) block;
+			tasklets[5] = (task_ioreg_t) (block>>8);
+			tasklets[6] = (task_ioreg_t) (block>>16);
+			tasklets[7] = (task_ioreg_t) (block>>24);
+			tasklets[8] = (task_ioreg_t) 0;
+			tasklets[9] = (task_ioreg_t) 0;
+//			tasklets[8] = (task_ioreg_t) (block>>32);
+//			tasklets[9] = (task_ioreg_t) (block>>40);
 #ifdef DEBUG
-		printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq->cmd==READ)?"read":"writ",
-			block, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
-		OUT_BYTE(block,IDE_SECTOR_REG);
-		OUT_BYTE(block>>=8,IDE_LCYL_REG);
-		OUT_BYTE(block>>=8,IDE_HCYL_REG);
-		OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+				drive->name,
+				(rq->cmd==READ)?"read":"writ",
+				block,
+				rq->nr_sectors,
+				(unsigned long) rq->buffer,
+				block);
+			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+				drive->name, tasklets[3], tasklets[2],
+				tasklets[9], tasklets[8], tasklets[7],
+				tasklets[6], tasklets[5], tasklets[4]);
+#endif
+			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
+			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
+			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
+			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
+			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
+
+			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
+			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
+			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
+			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
+			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
+			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+		} else {
+#ifdef DEBUG
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+				drive->name, (rq->cmd==READ)?"read":"writ",
+				block, rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+			OUT_BYTE(0x00, IDE_FEATURE_REG);
+			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
+			OUT_BYTE(block,IDE_SECTOR_REG);
+			OUT_BYTE(block>>=8,IDE_LCYL_REG);
+			OUT_BYTE(block>>=8,IDE_HCYL_REG);
+			OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+		}
 	} else {
 		unsigned int sect,head,cyl,track;
 		track = block / drive->sect;
@@ -392,6 +624,9 @@
 		OUT_BYTE(sect,IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
+
+		OUT_BYTE(0x00, IDE_FEATURE_REG);
+		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
 		OUT_BYTE(cyl,IDE_LCYL_REG);
 		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
 		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
@@ -413,7 +648,11 @@
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		}
 		return ide_started;
 	}
 	if (rq->cmd == WRITE) {
@@ -422,7 +661,11 @@
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		}
 		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
@@ -432,17 +675,17 @@
 			__cli();	/* local CPU only */
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-			/*
-			 * Ugh.. this part looks ugly because we MUST set up
-			 * the interrupt handler before outputting the first block
-			 * of data to be written.  If we hit an error (corrupted buffer list)
-			 * in ide_multwrite(), then we need to remove the handler/timer
-			 * before returning.  Fortunately, this NEVER happens (right?).
-			 *
-			 * Except when you get an error it seems...
-			 */
+	/*
+	 * Ugh.. this part looks ugly because we MUST set up
+	 * the interrupt handler before outputting the first block
+	 * of data to be written.  If we hit an error (corrupted buffer list)
+	 * in ide_multwrite(), then we need to remove the handler/timer
+	 * before returning.  Fortunately, this NEVER happens (right?).
+	 *
+	 * Except when you get an error it seems...
+	 */
 			hwgroup->wrq = *rq; /* scratchpad */
-			ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 			if (ide_multwrite(drive, drive->mult_count)) {
 				unsigned long flags;
 				spin_lock_irqsave(&io_request_lock, flags);
@@ -462,29 +705,47 @@
 	return ide_stopped;
 }
 
+#endif /* __TASKFILE__IO */
+
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+		taskfile.command = WIN_DOORLOCK;
 		check_disk_change(inode->i_rdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
 }
 
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+		taskfile.command = WIN_DOORUNLOCK;
 		invalidate_bdev(inode->i_bdev, 0);
-		if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
@@ -501,27 +762,234 @@
 }
 
 /*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long addr = 0;
+
+	if (!(drive->id->command_set_1 & 0x0400) &&
+	    !(drive->id->cfs_enable_2 & 0x0100))
+		return addr;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+	args.handler				= task_no_data_intr;
+
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long long addr = 0;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+	args.handler				= task_no_data_intr;
+
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr = ((__u64)high << 24) | low;
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+	ide_task_t args;
+	unsigned long addr_set = 0;
+	
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+	args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, read new maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr_set++;
+	return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+	ide_task_t args;
+	unsigned long long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+        args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr_set = ((__u64)high << 24) | low;
+	}
+	return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+	printk("%s: host protected area => %d\n", drive->name, flag);
+	return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
  */
 static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
+	unsigned long set_max = idedisk_read_native_max_address(drive);
+	unsigned long long capacity_2 = capacity;
+	unsigned long long set_max_ext;
 
+	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	if (id->cfs_enable_2 & 0x0400) {
+		capacity_2 = id->lba_capacity_2;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->head		= drive->bios_head = 255;
+		drive->sect		= drive->bios_sect = 63;
+		drive->select.b.lba	= 1;
+		set_max_ext = idedisk_read_native_max_address_ext(drive);
+		if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+			set_max_ext = idedisk_read_native_max_address_ext(drive);
+			set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+			if (set_max_ext) {
+				drive->capacity48 = capacity_2 = set_max_ext;
+				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+				drive->select.b.lba = 1;
+				drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+				drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+		}
+		drive->bios_cyl		= drive->cyl;
+		drive->capacity48	= capacity_2;
+		drive->capacity		= (unsigned long) capacity_2;
+		return;
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
 		capacity = id->lba_capacity;
 		drive->cyl = capacity / (drive->head * drive->sect);
 		drive->select.b.lba = 1;
 	}
+
+	if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+		set_max = idedisk_read_native_max_address(drive);
+		set_max = idedisk_set_max_address(drive, set_max);
+		if (set_max) {
+			drive->capacity = capacity = set_max;
+			drive->cyl = set_max / (drive->head * drive->sect);
+			drive->select.b.lba = 1;
+			drive->id->lba_capacity = capacity;
+		}
+#else /* !CONFIG_IDEDISK_STROKE */
+		printk("%s: setmax LBA %lu, native  %lu\n",
+			drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
+	}
+
 	drive->capacity = capacity;
+
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+                drive->capacity48 = id->lba_capacity_2;
+		drive->head = 255;
+		drive->sect = 63;
+		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+	}
 }
 
-static unsigned long idedisk_capacity (ide_drive_t  *drive)
+static unsigned long idedisk_capacity (ide_drive_t *drive)
 {
+	if (drive->id->cfs_enable_2 & 0x0400)
+		return (drive->capacity48 - drive->sect0);
 	return (drive->capacity - drive->sect0);
 }
 
@@ -530,23 +998,48 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		s->b.set_geometry = 0;
-		OUT_BYTE(drive->sect,IDE_SECTOR_REG);
-		OUT_BYTE(drive->cyl,IDE_LCYL_REG);
-		OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		ide_handler_t *handler = NULL;
+
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+		s->b.set_geometry	= 0;
+		taskfile.sector_number	= drive->sect;
+		taskfile.low_cylinder	= drive->cyl;
+		taskfile.high_cylinder	= drive->cyl>>8;
+		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
+		if (!IS_PDC4030_DRIVE) {
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_SPECIFY;
+			handler			= ide_handler_parser(&taskfile, &hobfile);
+		}
+		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_RESTORE;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->mult_req;
+			taskfile.command	= WIN_SETMULT;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->all) {
 		int special = s->all;
 		s->all = 0;
@@ -558,9 +1051,11 @@
 
 static void idedisk_pre_reset (ide_drive_t *drive)
 {
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
 	drive->special.all = 0;
-	drive->special.b.set_geometry = 1;
-	drive->special.b.recalibrate  = 1;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
 	if (OK_TO_RESET_CONTROLLER)
 		drive->mult_count = 0;
 	if (!drive->keep_settings && !drive->using_dma)
@@ -573,19 +1068,45 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_ENABLE;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_VALUES;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_THRESHOLDS;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -609,7 +1130,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_thresholds(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -628,7 +1149,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_values(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -656,14 +1177,31 @@
 
 static int set_multcount(ide_drive_t *drive, int arg)
 {
+#ifdef __TASKFILE__IO
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+
+	if (drive->special.b.set_multmode)
+		return -EBUSY;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.sector_count	= drive->mult_req;
+	taskfile.command	= WIN_SETMULT;
+	drive->mult_req		= arg;
+	drive->special.b.set_multmode = 1;
+	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+#else /* !__TASKFILE__IO */
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
 		return -EBUSY;
 	ide_init_drive_cmd (&rq);
+	rq.cmd = IDE_DRIVE_CMD;
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+#endif /* __TASKFILE__IO */
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
@@ -677,6 +1215,79 @@
 	return 0;
 }
 
+static int write_cache (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	taskfile.command	= WIN_SETFEATURES;
+
+	if (!(drive->id->cfs_enable_2 & 0x3000))
+		return 1;
+
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->wcache = arg;
+	return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.command	= WIN_STANDBYNOW1;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	if (drive->id->cfs_enable_2 & 0x2400) {
+		taskfile.command	= WIN_FLUSH_CACHE_EXT;
+	} else {
+		taskfile.command	= WIN_FLUSH_CACHE;
+	}
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+	taskfile.sector_count	= arg;
+
+	taskfile.command	= WIN_SETFEATURES;
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->acoustic = arg;
+	return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+	drive->addressing =  0;
+
+	if (!(drive->id->cfs_enable_2 & 0x0400))
+                return -EIO;
+
+	drive->addressing = arg;
+	return 0;
+}
+
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+	return (probe_lba_addressing(drive, arg));
+}
+
 static void idedisk_add_settings(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -686,15 +1297,18 @@
 	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
 	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
-	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	2,	&drive->mult_count,		set_multcount);
+	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
 	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	1,	&read_ahead[major],		NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	4096,			PAGE_SIZE,	1024,	&max_readahead[major][minor],	NULL);
-	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
+	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	1,	&max_sectors[major][minor],	NULL);
 	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
-	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
-	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
+	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
+	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
+ 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
+ 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
 static void idedisk_setup (ide_drive_t *drive)
@@ -764,7 +1378,6 @@
 	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
 	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-
 	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
 
 	/* Give size in megabytes (MB), not mebibytes (MiB). */
@@ -796,21 +1409,25 @@
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
 			drive->special.b.set_multmode = 1;
-#endif
+#endif	/* CONFIG_IDEDISK_MULTI_MODE */
 	}
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
-}
-
-static int idedisk_reinit (ide_drive_t *drive)
-{
-	return 0;
+	if (drive->id->cfs_enable_2 & 0x3000)
+		write_cache(drive, (id->cfs_enable_2 & 0x3000));
+	(void) probe_lba_addressing(drive, 1);
 }
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	return ide_unregister_subdriver(drive);
 }
 
+int idedisk_reinit(ide_drive_t *drive);
+
 /*
  *      IDE subdriver functions, registered with ide.c
  */
@@ -822,6 +1439,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
+	standby:		do_idedisk_standby,
+	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
 	end_request:		NULL,
 	ioctl:			NULL,
@@ -833,7 +1452,9 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	driver_reinit:		idedisk_reinit,
+	reinit:			idedisk_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
 };
 
 int idedisk_init (void);
@@ -846,6 +1467,32 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
+int idedisk_reinit (ide_drive_t *drive)
+{
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+
+	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy++;
+	idedisk_setup(drive);
+	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		(void) idedisk_cleanup(drive);
+		DRIVER(drive)->busy--;
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 static void __exit idedisk_exit (void)
 {
 	ide_drive_t *drive;
@@ -877,12 +1524,15 @@
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
+			DRIVER(drive)->busy--;
 			continue;
 		}
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idedisk_module);
diff -urN linux-2.4.19-pre2/drivers/ide/ide-dma.c linux-2.4.19-pre3/drivers/ide/ide-dma.c
--- linux-2.4.19-pre2/drivers/ide/ide-dma.c	Sun Sep  9 10:43:02 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-dma.c	Mon Mar 11 14:13:28 2002
@@ -123,6 +123,7 @@
 
 	{ "WDC AC11000H"	,	"ALL"		},
 	{ "WDC AC22100H"	,	"ALL"		},
+	{ "WDC AC31000H"	,	"ALL"		},
 	{ "WDC AC32500H"	,	"ALL"		},
 	{ "WDC AC33100H"	,	"ALL"		},
 	{ "WDC AC31600H"	,	"ALL"		},
@@ -282,6 +283,37 @@
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
+static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+{
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
+//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
 /*
  * ide_build_dmatable() prepares a dma request.
  * Returns 0 if all went okay, returns 1 otherwise.
@@ -299,7 +331,10 @@
 	int i;
 	struct scatterlist *sg;
 
-	HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
+		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	else
+		HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
 
 	if (!i)
 		return 0;
@@ -429,7 +464,14 @@
 	struct hd_driveid *id = drive->id;
 
 	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+		if ((id->dma_ultra >> 15) & 1) {
+			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
 		if ((id->dma_ultra >> 13) & 1) {
 			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
 		} else if ((id->dma_ultra >> 12) & 1) {
@@ -456,14 +498,24 @@
 
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	if (id && (id->capability & 1) && hwif->autodma) {
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	if (drive->media != ide_disk)
+		config_allows_dma = 0;
+#endif
+
+	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
 
+		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+				return hwif->dmaproc(ide_dma_on, drive);
 		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
 		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
 			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
@@ -495,7 +547,7 @@
 	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
 #endif /* DEBUG */
 
-#if 1
+#if 0
 	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
 #endif
 
@@ -550,7 +602,7 @@
  */
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-//	ide_hwgroup_t *hwgroup		= HWGROUP(drive);
+//	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	ide_hwif_t *hwif		= HWIF(drive);
 	unsigned long dma_base		= hwif->dma_base;
 	byte unit			= (drive->select.b.unit & 0x01);
@@ -582,11 +634,20 @@
 			if (drive->media != ide_disk)
 				return 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
+			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
 #else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
+			    (drive->addressing == 1)) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing) {
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			} else {
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			}
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
@@ -604,7 +665,7 @@
 			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
 		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
 			dma_stat = inb(dma_base+2);
-#if 0	/* do not set unless you know what you are doing */
+#if 0  /* do not set unless you know what you are doing */
 			if (dma_stat & 4) {
 				byte stat = GET_STAT();
 				outb(dma_base+2, dma_stat & 0xE4);
@@ -649,6 +710,8 @@
 				GET_STAT(), dma_stat);
 
 			return restart_request(drive);  // BUG: return types do not match!!
+//#else
+//			return HWGROUP(drive)->handler(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 		case ide_dma_retune:
 		case ide_dma_lostirq:
diff -urN linux-2.4.19-pre2/drivers/ide/ide-features.c linux-2.4.19-pre3/drivers/ide/ide-features.c
--- linux-2.4.19-pre2/drivers/ide/ide-features.c	Fri Feb  9 11:40:02 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-features.c	Mon Mar 11 14:13:28 2002
@@ -127,30 +127,14 @@
 		case XFER_UDMA_3:	return XFER_UDMA_2;
 		case XFER_UDMA_2:	return XFER_UDMA_1;
 		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
 		case XFER_UDMA_0:
-			if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
-			else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
-			else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_MW_DMA_2:	return XFER_MW_DMA_1;
-		case XFER_MW_DMA_1:	return XFER_MW_DMA_0;
-		case XFER_MW_DMA_0:
-			if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
-			else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
-			else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_SW_DMA_2:	return XFER_SW_DMA_1;
-		case XFER_SW_DMA_1:	return XFER_SW_DMA_0;
-		case XFER_SW_DMA_0:
-			{
-				return XFER_PIO_4;
-			}
-		case XFER_PIO_4:	return XFER_PIO_3;
-		case XFER_PIO_3:	return XFER_PIO_2;
-		case XFER_PIO_2:	return XFER_PIO_1;
-		case XFER_PIO_1:	return XFER_PIO_0;
-		case XFER_PIO_0:
-		default:		return XFER_PIO_SLOW;
+		default:		return XFER_PIO_4;
 	}
 }
 
@@ -216,11 +200,11 @@
  * in combination with the device (usually a disk) properly detect
  * and acknowledge each end of the ribbon.
  */
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect > XFER_UDMA_2) &&
-	    (feature == SETFEATURES_XFER)) {
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
 		if (!HWIF(drive)->udma_four) {
 			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
 			return 1;
@@ -243,11 +227,11 @@
  * 1 : Safe to update drive->id DMA registers.
  * 0 : OOPs not allowed.
  */
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect >= XFER_SW_DMA_0) &&
-	    (feature == SETFEATURES_XFER) &&
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
 	     drive->id->dma_1word))
@@ -389,3 +373,4 @@
 EXPORT_SYMBOL(set_transfer);
 EXPORT_SYMBOL(eighty_ninty_three);
 EXPORT_SYMBOL(ide_config_drive_speed);
+
diff -urN linux-2.4.19-pre2/drivers/ide/ide-floppy.c linux-2.4.19-pre3/drivers/ide/ide-floppy.c
--- linux-2.4.19-pre2/drivers/ide/ide-floppy.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/ide-floppy.c	Mon Mar 11 14:13:28 2002
@@ -71,11 +71,16 @@
  *                       including set_bit patch from Rusty Russel
  * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
  * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
+ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+ *                        fix a lost interrupt problem. It appears the busy
+ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ *                        drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
  * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code 
-                         to support new PocketZip drives 
+ *                        to support new PocketZip drives 
  */
 
-#define IDEFLOPPY_VERSION "0.99"
+#define IDEFLOPPY_VERSION "0.99.newide"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -278,6 +283,7 @@
 	 *	Last error information
 	 */
 	byte sense_key, asc, ascq;
+	byte ticks;		/* delay this long before sending packet command */
 	int progress_indication;
 
 	/*
@@ -291,6 +297,8 @@
 	unsigned long flags;			/* Status/Action flags */
 } idefloppy_floppy_t;
 
+#define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
+
 /*
  *	Floppy flag bits values.
  */
@@ -299,7 +307,7 @@
 #define IDEFLOPPY_USE_READ12		2	/* Use READ12/WRITE12 or READ10/WRITE10 */
 #define	IDEFLOPPY_FORMAT_IN_PROGRESS	3	/* Format in progress */
 #define IDEFLOPPY_CLIK_DRIVE	        4       /* Avoid commands not supported in Clik drive */
-
+#define IDEFLOPPY_ZIP_DRIVE		5	/* Requires BH algorithm for packets */
 
 /*
  *	ATAPI floppy drive packet commands
@@ -1003,6 +1011,11 @@
 	return ide_started;
 }
 
+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on drive type
+ */
 static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
 	ide_startstop_t startstop;
@@ -1023,6 +1036,56 @@
 	return ide_started;
 }
 
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * gets in trouble.
+ *
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or
+ * directly). In either case, when the device says it's ready for a 
+ * packet, we schedule the packet transfer to occur about 2-3 ticks
+ * later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+
+	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	ide_startstop_t startstop;
+	idefloppy_ireason_reg_t ireason;
+
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return startstop;
+	}
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	/* 
+	 * The following delay solves a problem with ATAPI Zip 100 drives where the
+	 * Busy flag was apparently being deasserted before the unit was ready to
+	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+	 * not be actually used until after the packet is moved in about 50 msec.
+	 */
+	ide_set_handler (drive, 
+	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	  floppy->ticks,			/* wait this long before "failing" */
+	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+	return ide_started;
+}
+
 /*
  *	Issue a packet command
  */
@@ -1031,6 +1094,7 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
 	int dma_ok = 0;
+	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
 	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1090,13 +1154,20 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+	/* Can we transfer the packet when we get the interrupt or wait? */
+	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	} else {
+		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+	}
+	
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idefloppy_transfer_pc (drive);
+		return (*pkt_xfer_routine) (drive);
 	}
 }
 
@@ -1916,13 +1987,18 @@
 {
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
+	idefloppy_floppy_t *floppy = drive->driver_data;
 
+/*
+ *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ */
 	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
+	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
 
 }
 
@@ -1956,20 +2032,25 @@
 
 	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
 	{
+		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
+		/* This value will be visible in the /proc/ide/hdx/settings */
+		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
+		for (i = 0; i < 1 << PARTN_BITS; i++)
+			max_sectors[major][minor + i] = 64;
+	}
+
+	/*
+	*      Guess what?  The IOMEGA Clik! drive also needs the
+	*      above fix.  It makes nasty clicking noises without
+	*      it, so please don't remove this.
+	*/
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
+	{
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
+		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
-  /*
-   *      Guess what?  The IOMEGA Clik! drive also needs the
-   *      above fix.  It makes nasty clicking noises without
-   *      it, so please don't remove this.
-   */
-	if (strncmp(drive->id->model, "IOMEGA Clik", 11) == 0) 
-  {
-    for (i = 0; i < 1 << PARTN_BITS; i++)
-      max_sectors[major][minor + i] = 64;
-    set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
-  }
+
 
 	(void) idefloppy_get_capacity (drive);
 	idefloppy_add_settings(drive);
@@ -2008,10 +2089,7 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2024,6 +2102,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
 	end_request:		idefloppy_end_request,
 	ioctl:			idefloppy_ioctl,
@@ -2035,7 +2115,9 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	driver_reinit:		idefloppy_reinit,
+	reinit:			idefloppy_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
 };
 
 int idefloppy_init (void);
@@ -2046,6 +2128,40 @@
 	NULL
 };
 
+int idefloppy_reinit (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
 static void __exit idefloppy_exit (void)
@@ -2097,7 +2213,9 @@
 			kfree (floppy);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idefloppy_module);
diff -urN linux-2.4.19-pre2/drivers/ide/ide-geometry.c linux-2.4.19-pre3/drivers/ide/ide-geometry.c
--- linux-2.4.19-pre2/drivers/ide/ide-geometry.c	Fri Nov  9 14:23:34 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-geometry.c	Mon Mar 11 14:13:28 2002
@@ -6,6 +6,8 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_BLK_DEV_IDE
+
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -40,7 +42,11 @@
  * Consequently, also the former "drive->present = 1" below was a mistake.
  *
  * Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
  */
+
 void probe_cmos_for_drives (ide_hwif_t *hwif)
 {
 #ifdef __i386__
@@ -80,9 +86,10 @@
 	}
 #endif
 }
+#endif /* CONFIG_BLK_DEV_IDE */
 
 
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -214,4 +221,4 @@
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -urN linux-2.4.19-pre2/drivers/ide/ide-pci.c linux-2.4.19-pre3/drivers/ide/ide-pci.c
--- linux-2.4.19-pre2/drivers/ide/ide-pci.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/ide-pci.c	Mon Mar 11 14:13:28 2002
@@ -12,6 +12,13 @@
  *  configuration of all PCI IDE interfaces present in a system.  
  */
 
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
+ */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -47,6 +54,8 @@
 #define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
 #define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
 #define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
 #define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
@@ -55,6 +64,7 @@
 #define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
 #define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
 #define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
+#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
 #define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
 #define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
 #define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
@@ -79,6 +89,7 @@
 #define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
 #define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
 #define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
+#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
 #define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
 #define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
 #define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
@@ -86,6 +97,7 @@
 #define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
 
 #define	IDE_IGNORE	((void *)-1)
+#define IDE_NO_DRIVER	((void *)-2)
 
 #ifdef CONFIG_BLK_DEV_AEC62XX
 extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
@@ -99,7 +111,7 @@
 #else
 #define PCI_AEC62XX	NULL
 #define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	NULL
+#define INIT_AEC62XX	IDE_NO_DRIVER
 #define DMA_AEC62XX	NULL
 #endif
 
@@ -115,7 +127,7 @@
 #else
 #define PCI_ALI15X3	NULL
 #define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	NULL
+#define INIT_ALI15X3	IDE_NO_DRIVER
 #define DMA_ALI15X3	NULL
 #endif
 
@@ -131,7 +143,7 @@
 #else
 #define PCI_AMD74XX	NULL
 #define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	NULL
+#define INIT_AMD74XX	IDE_NO_DRIVER
 #define DMA_AMD74XX	NULL
 #endif
 
@@ -149,7 +161,7 @@
 #ifdef __sparc_v9__
 #define INIT_CMD64X	IDE_IGNORE
 #else
-#define INIT_CMD64X	NULL
+#define INIT_CMD64X	IDE_NO_DRIVER
 #endif
 #endif
 
@@ -160,7 +172,7 @@
 #define INIT_CY82C693	&ide_init_cy82c693
 #else
 #define PCI_CY82C693	NULL
-#define INIT_CY82C693	NULL
+#define INIT_CY82C693	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_CS5530
@@ -170,7 +182,7 @@
 #define INIT_CS5530	&ide_init_cs5530
 #else
 #define PCI_CS5530	NULL
-#define INIT_CS5530	NULL
+#define INIT_CS5530	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT34X
@@ -199,7 +211,7 @@
 static byte hpt363_shared_pin;
 #define PCI_HPT366	NULL
 #define ATA66_HPT366	NULL
-#define INIT_HPT366	NULL
+#define INIT_HPT366	IDE_NO_DRIVER
 #define DMA_HPT366	NULL
 #endif
 
@@ -214,7 +226,7 @@
 extern void ide_init_opti621(ide_hwif_t *);
 #define INIT_OPTI621	&ide_init_opti621
 #else
-#define INIT_OPTI621	NULL
+#define INIT_OPTI621	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC_ADMA
@@ -241,9 +253,9 @@
 #define ATA66_PDC202XX	&ata66_pdc202xx
 #define INIT_PDC202XX	&ide_init_pdc202xx
 #else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
+#define PCI_PDC202XX	IDE_IGNORE
+#define ATA66_PDC202XX	IDE_IGNORE
+#define INIT_PDC202XX	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
@@ -256,19 +268,7 @@
 #else
 #define PCI_PIIX	NULL
 #define ATA66_PIIX	NULL
-#define INIT_PIIX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
-extern void ide_init_it8172(ide_hwif_t *);
-#define PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
+#define INIT_PIIX	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_IT8172
@@ -302,7 +302,7 @@
 #else
 #define PCI_SVWKS	NULL
 #define ATA66_SVWKS	NULL
-#define INIT_SVWKS	NULL
+#define INIT_SVWKS	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
@@ -315,7 +315,7 @@
 #else
 #define PCI_SIS5513	NULL
 #define ATA66_SIS5513	NULL
-#define INIT_SIS5513	NULL
+#define INIT_SIS5513	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SLC90E66
@@ -328,7 +328,7 @@
 #else
 #define PCI_SLC90E66	NULL
 #define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	NULL
+#define INIT_SLC90E66	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
@@ -363,7 +363,7 @@
 #else
 #define PCI_VIA82CXXX	NULL
 #define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	IDE_NO_DRIVER
 #define DMA_VIA82CXXX	NULL
 #endif
 
@@ -405,7 +405,7 @@
 #ifdef CONFIG_PDC202XX_FORCE
         {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
         {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
         {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
 #else /* !CONFIG_PDC202XX_FORCE */
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
@@ -413,11 +413,13 @@
 	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 #endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	/* Promise used a different PCI ident for the raid card apparently to try and
 	   prevent Linux detecting it and using our own raid code. We want to detect
 	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20268R,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -428,6 +430,11 @@
 	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+#ifndef CONFIG_BLK_DEV_CMD680
+	{DEVID_CMD680,	"CMD680",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+#else /* CONFIG_BLK_DEV_CMD680 */
+	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+#endif /* !CONFIG_BLK_DEV_CMD680 */
 	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
@@ -446,9 +453,10 @@
 	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
         {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -470,6 +478,9 @@
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 		case PCI_DEVICE_ID_ARTOP_ATP860:
 		case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -604,7 +615,15 @@
 		autodma = 1;
 #endif
 
-	pci_enable_device(dev);
+	if (d->init_hwif == IDE_NO_DRIVER) {
+		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
+		d->init_hwif = NULL;
+	}
+
+	if (pci_enable_device(dev)) {
+		printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+		return;
+	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
@@ -764,7 +783,8 @@
 		}
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
 			goto bypass_piix_dma;
-
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
+			goto bypass_legacy_dma;
 		if (hwif->udma_four) {
 			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
 		} else {
@@ -781,12 +801,15 @@
 			autodma = 0;
 		if (autodma)
 			hwif->autodma = 1;
+
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
@@ -797,6 +820,7 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
@@ -823,6 +847,7 @@
 			}
 		}
 #endif	/* CONFIG_BLK_DEV_IDEDMA */
+bypass_legacy_dma:
 bypass_piix_dma:
 bypass_umc_dma:
 		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
@@ -834,20 +859,60 @@
 		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
 }
 
+static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				byte irq = 0, irq2 = 0;
+				dev2 = findev;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+                                if (irq != irq2) {
+					dev2->irq = dev->irq;
+                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+                                }
+
+			}
+		}
+	}
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
+}
+
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	struct pci_dev *dev2 = NULL, *findev;
 	ide_pci_device_t *d2;
 	unsigned char pin1 = 0, pin2 = 0;
 	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
+	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"};
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
-
+	if (class_rev > 5)
+		class_rev = 5;
+	
 	strcpy(d->name, chipset_names[class_rev]);
 
 	switch(class_rev) {
@@ -914,6 +979,8 @@
 		return;	/* UM8886A/BF pair */
 	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
 		hpt366_device_order_fixup(dev, d);
+	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+		pdc20270_device_order_fixup(dev, d);
 	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 			printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
diff -urN linux-2.4.19-pre2/drivers/ide/ide-probe.c linux-2.4.19-pre3/drivers/ide/ide-probe.c
--- linux-2.4.19-pre2/drivers/ide/ide-probe.c	Mon Nov 26 05:29:17 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-probe.c	Mon Mar 11 14:13:28 2002
@@ -58,6 +58,11 @@
 	struct hd_driveid *id;
 
 	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	if (!id) {
+		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		goto err_kmalloc;
+	}
+
 	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
 	ide__sti();	/* local CPU only */
 	ide_fix_driveid(id);
@@ -76,8 +81,7 @@
 	if ((id->model[0] == 'P' && id->model[1] == 'M')
 	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-		drive->present = 0;
-		return;
+		goto err_misc;
 	}
 #endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
 
@@ -96,7 +100,7 @@
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
-		return;
+		goto err_misc;
 
 	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
 	printk("%s: %s, ", drive->name, id->model);
@@ -111,8 +115,7 @@
 #ifdef CONFIG_BLK_DEV_PDC4030
 		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
-			drive->present = 0;
-			return;
+			goto err_misc;
 		}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 		switch (type) {
@@ -174,6 +177,12 @@
 	printk("ATA DISK drive\n");
 	QUIRK_LIST(HWIF(drive),drive);
 	return;
+
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+	return;
 }
 
 /*
@@ -370,7 +379,7 @@
 	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
-		if (jiffies > timeout) {
+		if (time_after(jiffies, timeout)) {
 			printk("failed (timeout)\n");
 			return;
 		}
@@ -597,6 +606,12 @@
 
 	q->queuedata = HWGROUP(drive);
 	blk_init_queue(q, do_ide_request);
+
+	if (drive->media == ide_disk) {
+#ifdef CONFIG_BLK_DEV_ELEVATOR_NOOP
+		elevator_init(&q->elevator, ELEVATOR_NOOP);
+#endif
+	}
 }
 
 /*
@@ -685,6 +700,10 @@
 #else /* !CONFIG_IDEPCI_SHARE_IRQ */
 		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
 		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
@@ -752,18 +771,35 @@
 	int *bs, *max_sect, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
+#if 1
+	units = MAX_DRIVES;
+#else
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
 		if (hwif->drives[units-1].present)
 			break;
 	}
+#endif
+
 	minors    = units * (1<<PARTN_BITS);
 	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	if (!gd->sizes)
+		goto err_kmalloc_gd_sizes;
 	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!gd->part)
+		goto err_kmalloc_gd_part;
 	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!bs)
+		goto err_kmalloc_bs;
 	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_sect)
+		goto err_kmalloc_max_sect;
 	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_ra)
+		goto err_kmalloc_max_ra;
 
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
@@ -773,12 +809,10 @@
 	max_readahead[hwif->major] = max_ra;
 	for (unit = 0; unit < minors; ++unit) {
 		*bs++ = BLOCK_SIZE;
-#ifdef CONFIG_BLK_DEV_PDC4030
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 255);
-#else
-		/* IDE can do up to 128K per request. */
-		*max_sect++ = 255;
-#endif
+		/*
+		 * IDE can do up to 128K per request == 256
+		 */
+		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
 		*max_ra++ = vm_max_readahead;
 	}
 
@@ -804,6 +838,17 @@
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
+#if 1
+		char name[64];
+		ide_add_generic_settings(hwif->drives + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		sprintf (name, "host%d/bus%d/target%d/lun%d",
+			(hwif->channel && hwif->mate) ?
+			hwif->mate->index : hwif->index,
+			hwif->channel, unit, hwif->drives[unit].lun);
+		if (hwif->drives[unit].present)
+			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+#else
 		if (hwif->drives[unit].present) {
 			char name[64];
 
@@ -815,7 +860,23 @@
 			hwif->drives[unit].de =
 				devfs_mk_dir (ide_devfs_handle, name, NULL);
 		}
+#endif
 	}
+	return;
+
+err_kmalloc_max_ra:
+	kfree(max_sect);
+err_kmalloc_max_sect:
+	kfree(bs);
+err_kmalloc_bs:
+	kfree(gd->part);
+err_kmalloc_gd_part:
+	kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	return;
 }
 
 static int hwif_init (ide_hwif_t *hwif)
@@ -880,6 +941,19 @@
 	return hwif->present;
 }
 
+void export_ide_init_queue (ide_drive_t *drive)
+{
+	ide_init_queue(drive);
+}
+
+byte export_probe_for_drive (ide_drive_t *drive)
+{
+	return probe_for_drive(drive);
+}
+
+EXPORT_SYMBOL(export_ide_init_queue);
+EXPORT_SYMBOL(export_probe_for_drive);
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -913,6 +987,8 @@
 }
 
 #ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
 int init_module (void)
 {
 	unsigned int index;
@@ -921,12 +997,14 @@
 		ide_unregister(index);
 	ideprobe_init();
 	create_proc_ide_interfaces();
+	ide_xlate_1024_hook = ide_xlate_1024;
 	return 0;
 }
 
 void cleanup_module (void)
 {
 	ide_probe = NULL;
+	ide_xlate_1024_hook = 0;
 }
 MODULE_LICENSE("GPL");
 #endif /* MODULE */
diff -urN linux-2.4.19-pre2/drivers/ide/ide-proc.c linux-2.4.19-pre3/drivers/ide/ide-proc.c
--- linux-2.4.19-pre2/drivers/ide/ide-proc.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-proc.c	Mon Mar 11 14:13:28 2002
@@ -65,6 +65,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
+#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -447,7 +448,15 @@
 
 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
 {
-	return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.sector_count = 0x01;
+	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_ide_read_identify
@@ -457,7 +466,7 @@
 	int		len = 0, i = 0;
 
 	if (drive && !proc_ide_get_identify(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -588,7 +597,7 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+		len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -732,16 +741,38 @@
 	}
 }
 
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	int	d;
+	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
+	char name[64];
+//	ide_driver_t *driver = drive->driver;
 
-	for (d = 0; d < MAX_DRIVES; d++) {
-		ide_drive_t *drive = &hwif->drives[d];
-		ide_driver_t *driver = drive->driver;
+	if (drive->present && !drive->proc) {
+		drive->proc = proc_mkdir(drive->name, parent);
+		if (drive->proc)
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 
-		if (!drive->proc)
-			continue;
+/*
+ * assume that we have these already, however, should test FIXME!
+ * if (driver) {
+ *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ *      ide_add_proc_entries(drive->proc, driver->proc, drive);
+ * }
+ *
+ */
+		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+		ent = proc_symlink(drive->name, proc_ide_root, name);
+		if (!ent)
+			return;
+	}
+}
+
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	ide_driver_t *driver = drive->driver;
+
+	if (drive->proc) {
 		if (driver)
 			ide_remove_proc_entries(drive->proc, driver->proc);
 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
@@ -751,6 +782,19 @@
 	}
 }
 
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+//		ide_driver_t *driver = drive->driver;
+
+		if (drive->proc)
+			destroy_proc_ide_device(hwif, drive);
+	}
+}
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
diff -urN linux-2.4.19-pre2/drivers/ide/ide-tape.c linux-2.4.19-pre3/drivers/ide/ide-tape.c
--- linux-2.4.19-pre2/drivers/ide/ide-tape.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/ide/ide-tape.c	Mon Mar 11 14:13:28 2002
@@ -2418,26 +2418,26 @@
 	idetape_tape_t *tape = drive->driver_data;
 	int full = 125, empty = 75;
 
-	if (jiffies > tape->controlled_pipeline_head_time + 120 * HZ) {
+	if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
 		tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
 		tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
 		tape->controlled_last_pipeline_head = tape->pipeline_head;
 		tape->controlled_pipeline_head_time = jiffies;
 	}
-	if (jiffies > tape->controlled_pipeline_head_time + 60 * HZ)
+	if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
-	else if (jiffies > tape->controlled_previous_head_time)
+	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
 	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
-		if (jiffies > tape->uncontrolled_previous_head_time + 10 * HZ) {
+		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
 		}
 	} else {
 		tape->uncontrolled_previous_head_time = jiffies;
 		tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
-		if (jiffies > tape->uncontrolled_pipeline_head_time + 30 * HZ) {
+		if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 		}
 	}
@@ -2500,7 +2500,7 @@
 		tape->insert_time = jiffies;
 		tape->insert_size = 0;
 	}
-	if (jiffies > tape->insert_time)
+	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	if (jiffies - tape->avg_time >= HZ) {
 		tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
@@ -2680,11 +2680,11 @@
 		tape->reads_since_buffer_fill = 0;
 		tape->last_buffer_fill = jiffies;
 		idetape_queue_onstream_buffer_fill(drive);
-		if (jiffies > tape->insert_time)
+		if (time_after(jiffies, tape->insert_time))
 			tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 		return ide_stopped;
 	}
-	if (jiffies > tape->insert_time)
+	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
@@ -2740,7 +2740,7 @@
 			if (tape->onstream) {
 				if (tape->cur_frames - tape->reads_since_buffer_fill <= 0)
 					tape->req_buffer_fill = 1;
-				if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
+				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
 			pc = idetape_next_pc_storage (drive);
@@ -2756,7 +2756,7 @@
 			if (tape->onstream) {
 				if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames)
 					tape->req_buffer_fill = 1;
-				if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
+				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
@@ -3214,7 +3214,7 @@
 	 * Wait for the tape to become ready
 	 */
 	timeout += jiffies;
-	while (jiffies < timeout) {
+	while (time_before(jiffies, timeout)) {
 		idetape_create_test_unit_ready_cmd(&pc);
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
@@ -6132,10 +6132,7 @@
 
 #endif
 
-static int idetape_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idetape_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6148,6 +6145,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
 	ioctl:			idetape_blkdev_ioctl,
@@ -6158,7 +6157,9 @@
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
 	proc:			idetape_proc,
-	driver_reinit:		idetape_reinit,
+	reinit:			idetape_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
 };
 
 int idetape_init (void);
@@ -6181,6 +6182,92 @@
 	release:	idetape_chrdev_release,
 };
 
+int idetape_reinit (ide_drive_t *drive)
+{
+#if 0
+	idetape_tape_t *tape;
+	int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+	MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
+	if (!idetape_chrdev_present)
+		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+			idetape_chrdevs[minor].drive = NULL;
+
+	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+		ide_register_module (&idetape_module);
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return 0;
+	}
+	if (!idetape_chrdev_present &&
+	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return -EBUSY;
+	}
+	do {
+		if (!idetape_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			if (strstr(drive->id->model, "OnStream DI-30")) {
+				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+			} else {
+				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				continue;
+			}
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup (drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		tape->de_r =
+		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		tape->de_n =
+		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor + 128,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		devfs_register_tape (tape->de_r);
+		supported++; failed--;
+	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+	if (!idetape_chrdev_present && !supported) {
+		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	} else
+		idetape_chrdev_present = 1;
+	ide_register_module (&idetape_module);
+	MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+
+	return 0;
+#else
+	return 1;
+#endif
+}
+
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
 MODULE_LICENSE("GPL");
 
@@ -6205,7 +6292,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
-
+/* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
         printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
diff -urN linux-2.4.19-pre2/drivers/ide/ide-taskfile.c linux-2.4.19-pre3/drivers/ide/ide-taskfile.c
--- linux-2.4.19-pre2/drivers/ide/ide-taskfile.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/drivers/ide/ide-taskfile.c	Mon Mar 11 14:13:28 2002
@@ -0,0 +1,1723 @@
+/*
+ * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ *
+ *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ * IDE_DEBUG(__LINE__);
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  define __TASKFILE__IO
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#define DEBUG_TASKFILE	0	/* unset when fixed */
+
+#if DEBUG_TASKFILE
+#define DTF(x...) printk(##x)
+#else
+#define DTF(x...)
+#endif
+
+inline u32 task_read_24 (ide_drive_t *drive)
+{
+	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+	u16 *p = buffer;
+
+	while (wcount--) {
+		*p = *p << 8 | *p >> 8; p++;
+		*p = *p << 8 | *p >> 8; p++;
+	}
+}
+
+#if SUPPORT_VLB_SYNC
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static inline void task_vlb_sync (ide_ioreg_t port) {
+	(void) inb (port);
+	(void) inb (port);
+	(void) inb (port);
+}
+#endif /* SUPPORT_VLB_SYNC */
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			insl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			insl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				*ptr++ = inw_p(IDE_DATA_REG);
+				*ptr++ = inw_p(IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			insw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			outsl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			outsl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				outw_p(*ptr++, IDE_DATA_REG);
+				outw_p(*ptr++, IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			outsw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+
+static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	ata_input_data(drive, buffer, wcount);
+	if (drive->bswap)
+		ata_bswap_data(buffer, wcount);
+}
+
+static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	if (drive->bswap) {
+		ata_bswap_data(buffer, wcount);
+		ata_output_data(drive, buffer, wcount);
+		ata_bswap_data(buffer, wcount);
+	} else {
+		ata_output_data(drive, buffer, wcount);
+	}
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (task->handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+#if 0
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+#else
+		ide_startstop_t startstop;
+
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+				drive->name,
+				drive->mult_count ? "MULTWRITE" : "WRITE");
+			return startstop;
+		}
+		/* (ks/hs): Fixed Multi Write */
+		if ((taskfile->command != WIN_MULTWRITE) &&
+		    (taskfile->command != WIN_MULTWRITE_EXT)) {
+			struct request *rq = HWGROUP(drive)->rq;
+		/* For Write_sectors we need to stuff the first sector */
+			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+			rq->current_nr_sectors--;
+		} else {
+		/* Stuff first sector(s) by implicitly calling the handler */
+			if (!(drive_is_ready(drive))) {
+			/* FIXME: Replace hard-coded 100, error handling? */
+				int i;
+				for (i=0; i<100; i++) {
+					if (drive_is_ready(drive))
+						break;
+				}
+			}
+			return task->handler(drive);
+		}
+#endif
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+{
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (*handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (handler != NULL) {
+		ide_set_handler (drive, handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+}
+
+#if 0
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+
+	/*
+	 * (KS) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
+		}
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
+		}
+        }
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	if (task->tf_out_flags.b.data) {
+		unsigned short data =  taskfile->data + (hobfile->data << 8);
+		OUT_WORD (data, IDE_DATA_REG);
+	}
+
+	/* (KS) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+
+
+	/* (KS) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (KS) Do not modify the specified taskfile. We want to have a
+	 * universal pass through, so we must execute ALL specified values.
+	 *
+	 * (KS) The drive head register is mandatory.
+	 * Don't care about the out flags !
+	 */
+	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+#if 0
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+#else
+		ide_startstop_t startstop;
+
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+
+		/*
+		 * (KS) The drive command register is also mandatory.
+		 * Don't care about the out flags !
+		 */
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+				drive->name,
+				drive->mult_count ? "MULTWRITE" : "WRITE");
+			return startstop;
+		}
+		/* (ks/hs): Fixed Multi Write */
+		if ((taskfile->command != WIN_MULTWRITE) &&
+		    (taskfile->command != WIN_MULTWRITE_EXT)) {
+			struct request *rq = HWGROUP(drive)->rq;
+		/* For Write_sectors we need to stuff the first sector */
+			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+			rq->current_nr_sectors--;
+		} else {
+		/* Stuff first sector(s) by implicitly calling the handler */
+			if (!(drive_is_ready(drive))) {
+			/* FIXME: Replace hard-coded 100, error handling? */
+				int i;
+				for (i=0; i<100; i++) {
+					if (drive_is_ready(drive))
+						break;
+				}
+			}
+			return task->handler(drive);
+		}
+#endif
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+#endif
+
+#if 0
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
+
+	__save_flags (flags);	/* local CPU only */
+	ide__sti();		/* local CPU only */
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif  /* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = task_read_24(drive);
+					OUT_BYTE(0x80, IDE_CONTROL_REG);
+					high = task_read_24(drive);
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld", sectors);
+				} else {
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						  (IN_BYTE(IDE_HCYL_REG)<<8) +
+						   IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive)->rq)
+					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif  /* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	__restore_flags (flags);	/* local CPU only */
+	return err;
+}
+
+/*
+ * Clean up after success/failure of an explicit taskfile operation.
+ */
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+{
+	unsigned long flags;
+	struct request *rq;
+	ide_task_t *args;
+	task_ioreg_t command;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	args = (ide_task_t *) rq->special;
+
+	command = args->tfRegister[IDE_COMMAND_OFFSET];
+
+	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+	args->tfRegister[IDE_ERROR_OFFSET]   = err;
+	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+	if ((drive->id->command_set_2 & 0x0400) &&
+	    (drive->id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+	}
+
+/*	taskfile_settings_update(drive, args, command); */
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+void task_try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		taskfile_input_data (drive, buffer, wcount);
+	}
+}
+
+/*
+ * taskfile_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+        err = taskfile_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			else if (err & TRK0_ERR)	/* help it find track zero */
+                                rq->errors |= ERROR_RECAL;
+                }
+                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+                        task_try_to_flush_leftover_data(drive);
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
+
+	if (rq->errors >= ERROR_MAX) {
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(0, HWGROUP(drive));
+		else
+			ide_end_request(0, HWGROUP(drive));
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+#endif
+
+/*
+ * Handler for special commands without a data phase from ide-disk
+ */
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+		drive->mult_count = drive->mult_req;
+	} else {
+		drive->mult_req = drive->mult_count = 0;
+		drive->special.b.recalibrate = 1;
+		(void) ide_dump_status(drive, "set_multmode", stat);
+	}
+	return ide_stopped;
+}
+
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+		return ide_stopped;
+
+	if (stat & (ERR_STAT|DRQ_STAT))
+		return ide_error(drive, "set_geometry_intr", stat);
+
+	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+	byte stat = GET_STAT();
+
+	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+		return ide_error(drive, "recal_intr", stat);
+	return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	byte stat		= GET_STAT();
+
+	ide__sti();	/* local CPU only */
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
+
+	if (args)
+		ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_in_intr", stat);
+		}
+		if (!(stat & BUSY_STAT)) {
+			DTF("task_in_intr to Soon wait for next interrupt\n");
+			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			return ide_started;  
+		}
+	}
+	DTF("stat: %02x\n", stat);
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+
+	drive->io_32bit = 0;
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	drive->io_32bit = io_32bit;
+
+	if (--rq->current_nr_sectors <= 0) {
+		/* (hs): swapped next 2 lines */
+		DTF("Request Ended stat: %02x\n", GET_STAT());
+		ide_end_request(1, HWGROUP(drive));
+	} else {
+		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+#undef ALTSTAT_SCREW_UP
+
+#ifdef ALTSTAT_SCREW_UP
+/*
+ * (ks/hs): Poll Alternate Status Register to ensure
+ * that drive is not busy.
+ */
+byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
+{
+	int i;
+
+	DTF("multi%s: ASR = %x\n", msg, stat);
+	if (stat & BUSY_STAT) {
+		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
+		for (i=0; i<100; i++) {
+			stat = GET_ALTSTAT();
+			if ((stat & BUSY_STAT) == 0)
+				break;
+		}
+	}
+	/*
+	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 */
+	return(GET_STAT());
+}
+
+/*
+ * (ks/hs): Poll Alternate status register to wait for drive
+ * to become ready for next transfer
+ */
+byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
+{
+	/* (ks/hs): FIXME: Error handling, time-out? */
+	while (stat & BUSY_STAT)
+		stat = GET_ALTSTAT();
+	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
+	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
+}
+#endif /* ALTSTAT_SCREW_UP */
+
+/*
+ * Handler for command with Read Multiple
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulin_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): Fixed Multi-Sector transfer */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		/*
+		 * (ks/hs): Drive supports multi-sector transfer,
+		 * drive->mult_count was not set
+		 */
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+		pBuf, nsect, rq->current_nr_sectors);
+	drive->io_32bit = 0;
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+	ide_end_request(1, HWGROUP(drive));
+	return ide_stopped;
+}
+
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+		return startstop;
+	}
+
+	/* (ks/hs): Fixed Multi Write */
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
+	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+		/* For Write_sectors we need to stuff the first sector */
+		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+		rq->current_nr_sectors--;
+		return ide_started;
+	} else {
+		/*
+		 * (ks/hs): Stuff the first sector(s)
+		 * by implicitly calling the handler
+		 */
+		if (!(drive_is_ready(drive))) {
+			int i;
+			/*
+			 * (ks/hs): FIXME: Replace hard-coded
+			 *               100, error handling?
+			 */
+			for (i=0; i<100; i++) {
+				if (drive_is_ready(drive))
+					break;
+			}
+		}
+		return args->handler(drive);
+	}
+	return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+
+	if (!rq->current_nr_sectors) { 
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		return ide_error(drive, "task_out_intr", stat);
+	}
+	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+		rq = HWGROUP(drive)->rq;
+		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors--;
+	}
+
+	if (rq->current_nr_sectors <= 0) {
+		ide_end_request(1, HWGROUP(drive));
+	} else {
+		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	char *pBuf		= NULL;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent
+	 */
+	if (rq->current_nr_sectors == 0) {
+		if (stat & (ERR_STAT|DRQ_STAT))
+			return ide_error(drive, "task_mulout_intr", stat);
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulout_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (hwgroup->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): See task_mulin_intr */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+		pBuf, nsect, rq->current_nr_sectors);
+	drive->io_32bit = 0;
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	rq->current_nr_sectors -= nsect;
+	if (hwgroup->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/* Called by internal to feature out type of command being called */
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+				/* IDE_DRIVE_TASK_RAW_WRITE */
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+//		case WIN_WRITEDMA:
+//		case WIN_WRITEDMA_QUEUED:
+//		case WIN_WRITEDMA_EXT:
+//		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_WRITE:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return &pre_task_out_intr;
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_SMART:
+			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
+				return &pre_task_out_intr;
+		default:
+			break;
+	}
+	return(NULL);
+}
+
+/* Called by internal to feature out type of command being called */
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ_BUFFER:
+		case WIN_READ:
+		case WIN_READ_EXT:
+			return &task_in_intr;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+		case WIN_DOWNLOAD_MICROCODE:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_WRITE_BUFFER:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+			return &task_out_intr;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return &task_mulin_intr;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &task_mulout_intr;
+		case WIN_SMART:
+			switch(taskfile->feature) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return &task_in_intr;
+				case SMART_WRITE_LOG_SECTOR:
+					return &task_out_intr;
+				default:
+					return &task_no_data_intr;
+			}
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+			return &task_no_data_intr;
+		case WIN_SPECIFY:
+			return &set_geometry_intr;
+		case WIN_RESTORE:
+			return &recal_intr;
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+			return &task_no_data_intr;
+		case WIN_SETMULT:
+			return &set_multmode_intr;
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+		case WIN_SETFEATURES:
+			return &task_no_data_intr;
+		case DISABLE_SEAGATE:
+		case EXABYTE_ENABLE_NEST:
+			return &task_no_data_intr;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+#endif
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return(NULL);
+	}	
+}
+
+/* Called by ioctl to feature out type of command being called */
+int ide_cmd_type_parser (ide_task_t *args)
+{
+	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
+	args->handler = ide_handler_parser(taskfile, hobfile);
+
+	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ:
+		case WIN_READ_BUFFER:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITE:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_MULTREAD:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+			return IDE_DRIVE_TASK_OUT;
+		case WIN_SMART:
+			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return IDE_DRIVE_TASK_IN;
+				case SMART_WRITE_LOG_SECTOR:
+					return IDE_DRIVE_TASK_OUT;
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+#endif
+		case WIN_SETFEATURES:
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_XFER:
+					return IDE_DRIVE_TASK_SET_XFER;
+				case SETFEATURES_DIS_DEFECT:
+				case SETFEATURES_EN_APM:
+				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_EN_RI:
+				case SETFEATURES_EN_SI:
+				case SETFEATURES_DIS_RPOD:
+				case SETFEATURES_DIS_WCACHE:
+				case SETFEATURES_EN_DEFECT:
+				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RLA:
+				case SETFEATURES_PREFETCH:
+				case SETFEATURES_EN_RPOD:
+				case SETFEATURES_DIS_RI:
+				case SETFEATURES_DIS_SI:
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+		case WIN_NOP:
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+		case WIN_SPECIFY:
+		case WIN_RESTORE:
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case DISABLE_SEAGATE:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+		case WIN_SETMULT:
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case EXABYTE_ENABLE_NEST:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+			return IDE_DRIVE_TASK_NO_DATA;
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return IDE_DRIVE_TASK_INVALID;
+	}
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_taskfile (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_TASK_NO_DATA;
+}
+
+/*
+ * This is kept for internal use only !!!
+ * This is an internal call and nobody in user-space has a damn
+ * reason to call this taskfile.
+ *
+ * ide_raw_taskfile is the one that user-space executes.
+ */
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
+{
+	struct request rq;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
+	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
+	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
+	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
+	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
+	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
+	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
+	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
+
+	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
+	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+
+	ide_init_drive_taskfile(&rq);
+	/* This is kept for internal use only !!! */
+	args.command_type = ide_cmd_type_parser (&args);
+	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
+
+	rq.cmd = IDE_DRIVE_TASKFILE;
+	rq.buffer = buf;
+	rq.special = &args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+{
+	struct request rq;
+	ide_init_drive_taskfile(&rq);
+	rq.cmd = IDE_DRIVE_TASKFILE;
+	rq.buffer = buf;
+
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+
+	rq.special = args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+char * ide_ioctl_verbose (unsigned int cmd)
+{
+	return("unknown");
+}
+
+char * ide_task_cmd_verbose (byte task)
+{
+	return("unknown");
+}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+/*
+ *  The taskfile glue table
+ *
+ *  reqtask.data_phase	reqtask.req_cmd
+ *  			args.command_type		args.handler
+ *
+ *  TASKFILE_P_OUT_DMAQ	??				??
+ *  TASKFILE_P_IN_DMAQ	??				??
+ *  TASKFILE_P_OUT_DMA	??				??
+ *  TASKFILE_P_IN_DMA	??				??
+ *  TASKFILE_P_OUT	??				??
+ *  TASKFILE_P_IN	??				??
+ *
+ *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_IN_OUT	??				??
+ *
+ *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
+ *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
+ *
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
+ *
+ *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
+ *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
+ *
+ *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
+ *  			IDE_DRIVE_TASK_INVALID
+ *
+ */
+
+#define MAX_DMA		(256*SECTOR_WORDS)
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	ide_task_request_t	*req_task;
+	ide_task_t		args;
+
+	byte *outbuf		= NULL;
+	byte *inbuf		= NULL;
+	task_ioreg_t *argsptr	= args.tfRegister;
+	task_ioreg_t *hobsptr	= args.hobRegister;
+	int err			= 0;
+	int tasksize		= sizeof(struct ide_task_request_s);
+	int taskin		= 0;
+	int taskout		= 0;
+
+	req_task = kmalloc(tasksize, GFP_KERNEL);
+	if (req_task == NULL) return -ENOMEM;
+	memset(req_task, 0, tasksize);
+	if (copy_from_user(req_task, (void *) arg, tasksize)) {
+		kfree(req_task);
+		return -EFAULT;
+	}
+
+	taskout = (int) req_task->out_size;
+	taskin  = (int) req_task->in_size;
+
+	if (taskout) {
+		int outtotal = tasksize;
+		outbuf = kmalloc(taskout, GFP_KERNEL);
+		if (outbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(outbuf, 0, taskout);
+		if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		inbuf = kmalloc(taskin, GFP_KERNEL);
+		if (inbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(inbuf, 0, taskin);
+		if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
+	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+	args.tf_in_flags  = req_task->in_flags;
+	args.tf_out_flags = req_task->out_flags;
+	args.data_phase   = req_task->data_phase;
+	args.command_type = req_task->req_cmd;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
+		drive->name,
+		ide_ioctl_verbose(cmd),
+		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	switch(req_task->data_phase) {
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_IN_OUT:
+#if 0
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+#else
+			err = -EFAULT;
+			goto abort;
+#endif
+		case TASKFILE_MULTI_OUT:
+			if (drive->mult_count) {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_mulout_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, outbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Write " \
+					"multcount is not set\n",
+					 drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_OUT:
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_MULTI_IN:
+			if (drive->mult_count) {
+				args.prehandler = NULL;
+				args.handler = &task_mulin_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, inbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Read failure " \
+					"multcount is not set\n",
+					drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_IN:
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_NO_DATA:
+			args.prehandler = NULL;
+			args.handler = &task_no_data_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, NULL);
+			break;
+		default:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = -EFAULT;
+			goto abort;
+	}
+
+	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+	req_task->in_flags  = args.tf_in_flags;
+	req_task->out_flags = args.tf_out_flags;
+
+	if (copy_to_user((void *)arg, req_task, tasksize)) {
+		err = -EFAULT;
+		goto abort;
+	}
+	if (taskout) {
+		int outtotal = tasksize;
+		if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+abort:
+	kfree(req_task);
+	if (outbuf != NULL)
+		kfree(outbuf);
+	if (inbuf != NULL)
+		kfree(inbuf);
+	return err;
+}
+
+EXPORT_SYMBOL(task_read_24);
+EXPORT_SYMBOL(do_rw_taskfile);
+EXPORT_SYMBOL(do_taskfile);
+// EXPORT_SYMBOL(flagged_taskfile);
+
+//EXPORT_SYMBOL(ide_end_taskfile);
+
+EXPORT_SYMBOL(set_multmode_intr);
+EXPORT_SYMBOL(set_geometry_intr);
+EXPORT_SYMBOL(recal_intr);
+
+EXPORT_SYMBOL(task_no_data_intr);
+EXPORT_SYMBOL(task_in_intr);
+EXPORT_SYMBOL(task_mulin_intr);
+EXPORT_SYMBOL(pre_task_out_intr);
+EXPORT_SYMBOL(task_out_intr);
+EXPORT_SYMBOL(task_mulout_intr);
+
+EXPORT_SYMBOL(ide_init_drive_taskfile);
+EXPORT_SYMBOL(ide_wait_taskfile);
+EXPORT_SYMBOL(ide_raw_taskfile);
+EXPORT_SYMBOL(ide_pre_handler_parser);
+EXPORT_SYMBOL(ide_handler_parser);
+EXPORT_SYMBOL(ide_cmd_type_parser);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+
+#if 0
+{
+
+{ /* start cdrom */
+
+	struct cdrom_info *info = drive->driver_data;
+
+	if (info->dma) {
+		if (info->cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (info->cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
+			printk("ide-cd: DMA set, but not allowed\n");
+		}
+	}
+
+	/* Set up the controller registers. */
+	OUT_BYTE (info->dma, IDE_FEATURE_REG);
+	OUT_BYTE (0, IDE_NSECTOR_REG);
+	OUT_BYTE (0, IDE_SECTOR_REG);
+
+	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+
+	if (info->dma)
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
+	} else {
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return (*handler) (drive);
+	}
+
+} /* end cdrom */
+
+{ /* start floppy */
+
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	idefloppy_bcount_reg_t bcount;
+	int dma_ok = 0;
+
+	floppy->pc=pc;		/* Set the current packet command */
+
+	pc->retries++;
+	pc->actually_transferred=0; /* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+} /* end floppy */
+
+{ /* start tape */
+
+	idetape_tape_t *tape = drive->driver_data;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
+	} else {
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idetape_transfer_pc(drive);
+	}
+
+} /* end tape */
+
+}
+#endif
+
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+	switch(req_task->data_phase) {
+		case TASKFILE_P_OUT_DMAQ:
+		case TASKFILE_P_IN_DMAQ:
+		case TASKFILE_P_OUT_DMA:
+		case TASKFILE_P_IN_DMA:
+		case TASKFILE_P_OUT:
+		case TASKFILE_P_IN:
+	}
+#endif
+	return -ENOMSG;
+}
+
+EXPORT_SYMBOL(pkt_taskfile_ioctl);
+
+#endif /* CONFIG_PKT_TASK_IOCTL */
diff -urN linux-2.4.19-pre2/drivers/ide/ide.c linux-2.4.19-pre3/drivers/ide/ide.c
--- linux-2.4.19-pre2/drivers/ide/ide.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/ide.c	Mon Mar 11 14:13:28 2002
@@ -149,6 +149,7 @@
 #include <linux/ide.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
+#include <linux/reboot.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -162,6 +163,16 @@
 #include <linux/kmod.h>
 #endif /* CONFIG_KMOD */
 
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  define __TASKFILE__IO
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef __TASKFILE__IO
+#else /* !__TASKFILE__IO */
+#endif /* __TASKFILE__IO */
+
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
 
@@ -515,7 +526,8 @@
 /*
  * Needed for PCI irq sharing
  */
-static inline int drive_is_ready (ide_drive_t *drive)
+//static inline
+int drive_is_ready (ide_drive_t *drive)
 {
 	byte stat = 0;
 	if (drive->waiting_for_dma)
@@ -809,7 +821,11 @@
 	 */
 	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
 	udelay(10);			/* more than enough time */
-	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	if (drive->quirk_list == 2) {
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
+	} else {
+		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
@@ -836,6 +852,13 @@
 	return do_reset1 (drive, 0);
 }
 
+static inline u32 read_24 (ide_drive_t *drive)
+{
+	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
 /*
  * Clean up after success/failure of an explicit drive cmd
  */
@@ -848,26 +871,66 @@
 	rq = HWGROUP(drive)->rq;
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	if (rq->cmd == IDE_DRIVE_CMD) {
-		byte *args = (byte *) rq->buffer;
-		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-		if (args) {
-			args[0] = stat;
-			args[1] = err;
-			args[2] = IN_BYTE(IDE_NSECTOR_REG);
-		}
-	} else if (rq->cmd == IDE_DRIVE_TASK) {
-		byte *args = (byte *) rq->buffer;
-		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-		if (args) {
-			args[0] = stat;
-			args[1] = err;
-			args[2] = IN_BYTE(IDE_NSECTOR_REG);
-			args[3] = IN_BYTE(IDE_SECTOR_REG);
-			args[4] = IN_BYTE(IDE_LCYL_REG);
-			args[5] = IN_BYTE(IDE_HCYL_REG);
-			args[6] = IN_BYTE(IDE_SELECT_REG);
+	switch(rq->cmd) {
+		case IDE_DRIVE_CMD:
+		{
+			byte *args = (byte *) rq->buffer;
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = IN_BYTE(IDE_NSECTOR_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASK:
+		{
+			byte *args = (byte *) rq->buffer;
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = IN_BYTE(IDE_NSECTOR_REG);
+				args[3] = IN_BYTE(IDE_SECTOR_REG);
+				args[4] = IN_BYTE(IDE_LCYL_REG);
+				args[5] = IN_BYTE(IDE_HCYL_REG);
+				args[6] = IN_BYTE(IDE_SELECT_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASKFILE:
+		{
+			ide_task_t *args = (ide_task_t *) rq->special;
+			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			if (args) {
+				if (args->tf_in_flags.b.data) {
+					unsigned short data			= IN_WORD(IDE_DATA_REG);
+					args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+					args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+				}
+				args->tfRegister[IDE_ERROR_OFFSET]   = err;
+				args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+				args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+				args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+				args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+				args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+				}
+			}
+			break;
 		}
+		default:
+			break;
 	}
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
@@ -917,19 +980,32 @@
 			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
 			printk("}");
 			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				byte cur = IN_BYTE(IDE_SELECT_REG);
-				if (cur & 0x40) {	/* using LBA? */
-					printk(", LBAsect=%ld", (unsigned long)
-					 ((cur&0xf)<<24)
-					 |(IN_BYTE(IDE_HCYL_REG)<<16)
-					 |(IN_BYTE(IDE_LCYL_REG)<<8)
-					 | IN_BYTE(IDE_SECTOR_REG));
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = read_24(drive);
+					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
+
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low);
 				} else {
-					printk(", CHS=%d/%d/%d",
-					 (IN_BYTE(IDE_HCYL_REG)<<8) +
-					  IN_BYTE(IDE_LCYL_REG),
-					  cur & 0xf,
-					  IN_BYTE(IDE_SECTOR_REG));
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (IN_BYTE(IDE_HCYL_REG)<<8) +
+						  IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
 				}
 				if (HWGROUP(drive) && HWGROUP(drive)->rq)
 					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
@@ -980,6 +1056,13 @@
 		ide_end_drive_cmd(drive, stat, err);
 		return ide_stopped;
 	}
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+//		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
@@ -1141,62 +1224,125 @@
  */
 static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
-	byte *args = rq->buffer;
-	if (args && rq->cmd == IDE_DRIVE_TASK) {
-		byte sel;
+ 	switch(rq->cmd) {
+ 		case IDE_DRIVE_TASKFILE:
+ 		{
+ 			ide_task_t *args = rq->special;
+ 
+ 			if (!(args)) break;
+ 
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	{
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
+	}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+//			if (args->tf_out_flags.all == 0) {
+ 			do_taskfile(drive,
+ 				(struct hd_drive_task_hdr *)&args->tfRegister,
+				(struct hd_drive_hob_hdr *)&args->hobRegister,
+ 				args->handler);
+//			} else {
+//				return flagged_taskfile(drive, args);
+//			} 
+
+ 			if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+ 			     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+			      args->prehandler && args->handler)
+				return args->prehandler(drive, rq);
+ 			return ide_started;
+ 		}
+ 		case IDE_DRIVE_TASK:
+ 		{
+ 			byte *args = rq->buffer;
+ 			byte sel;
+ 
+ 			if (!(args)) break;
 #ifdef DEBUG
-		printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
-			drive->name,
-			args[0], args[1], args[2], args[3],
-			args[4], args[5], args[6], args[7]);
+ 			printk("%s: DRIVE_TASK_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("fr=0x%02x ", args[1]);
+ 			printk("ns=0x%02x ", args[2]);
+ 			printk("sc=0x%02x ", args[3]);
+ 			printk("lcyl=0x%02x ", args[4]);
+ 			printk("hcyl=0x%02x ", args[5]);
+ 			printk("sel=0x%02x\n", args[6]);
 #endif
-		OUT_BYTE(args[1], IDE_FEATURE_REG);
-		OUT_BYTE(args[3], IDE_SECTOR_REG);
-		OUT_BYTE(args[4], IDE_LCYL_REG);
-		OUT_BYTE(args[5], IDE_HCYL_REG);
-		sel = (args[6] & ~0x10);
-		if (drive->select.b.unit)
-			sel |= 0x10;
-		OUT_BYTE(sel, IDE_SELECT_REG);
-		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
-		return ide_started;
-	} else if (args) {
+ 			OUT_BYTE(args[1], IDE_FEATURE_REG);
+ 			OUT_BYTE(args[3], IDE_SECTOR_REG);
+ 			OUT_BYTE(args[4], IDE_LCYL_REG);
+ 			OUT_BYTE(args[5], IDE_HCYL_REG);
+ 			sel = (args[6] & ~0x10);
+ 			if (drive->select.b.unit)
+ 				sel |= 0x10;
+ 			OUT_BYTE(sel, IDE_SELECT_REG);
+ 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		case IDE_DRIVE_CMD:
+ 		{
+ 			byte *args = rq->buffer;
+ 
+ 			if (!(args)) break;
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
-		 drive->name, args[0], args[1], args[2], args[3]);
+ 			printk("%s: DRIVE_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("sc=0x%02x ", args[1]);
+ 			printk("fr=0x%02x ", args[2]);
+ 			printk("xx=0x%02x\n", args[3]);
 #endif
-		if (args[0] == WIN_SMART) {
-			OUT_BYTE(0x4f, IDE_LCYL_REG);
-			OUT_BYTE(0xc2, IDE_HCYL_REG);
-			OUT_BYTE(args[2],IDE_FEATURE_REG);
-			OUT_BYTE(args[1],IDE_SECTOR_REG);
-			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
-			return ide_started;
-		}
-		OUT_BYTE(args[2],IDE_FEATURE_REG);
-		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-		return ide_started;
-	} else {
-		/*
-		 * NULL is actually a valid way of waiting for
-		 * all current requests to be flushed from the queue.
-		 */
+ 			if (args[0] == WIN_SMART) {
+ 				OUT_BYTE(0x4f, IDE_LCYL_REG);
+ 				OUT_BYTE(0xc2, IDE_HCYL_REG);
+ 				OUT_BYTE(args[2],IDE_FEATURE_REG);
+ 				OUT_BYTE(args[1],IDE_SECTOR_REG);
+ 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ 				return ide_started;
+ 			}
+ 			OUT_BYTE(args[2],IDE_FEATURE_REG);
+ 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		default:
+ 			break;
+ 	}
+ 	/*
+ 	 * NULL is actually a valid way of waiting for
+ 	 * all current requests to be flushed from the queue.
+ 	 */
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD (null)\n", drive->name);
+ 	printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-		return ide_stopped;
-	}
+ 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ 	return ide_stopped;
 }
 
 /*
  * start_request() initiates handling of a new I/O request
+ * needed to reverse the perverted changes anonymously made back
+ * 2.3.99-pre6
  */
-static ide_startstop_t start_request (ide_drive_t *drive)
+static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
 	unsigned long block, blockend;
-	struct request *rq = blkdev_entry_next_request(&drive->queue.queue_head);
 	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
@@ -1245,8 +1391,13 @@
 		return startstop;
 	}
 	if (!drive->special.all) {
-		if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
-			return execute_drive_cmd(drive, rq);
+		switch(rq->cmd) {
+			case IDE_DRIVE_CMD:
+			case IDE_DRIVE_TASK:
+			case IDE_DRIVE_TASKFILE:
+				return execute_drive_cmd(drive, rq);
+			default:
+				break;
 		}
 		if (drive->driver != NULL) {
 			return (DRIVER(drive)->do_request(drive, rq, block));
@@ -1267,13 +1418,15 @@
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned long flags;
+	struct request *rq;
 
 	spin_lock_irqsave(&io_request_lock, flags);
 	hwgroup->handler = NULL;
 	del_timer(&hwgroup->timer);
+	rq = hwgroup->rq;
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	return start_request(drive);
+	return start_request(drive, rq);
 }
 
 /*
@@ -1370,10 +1523,11 @@
 /* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
  *         into life on wakeup from machine sleep.
  */ 
-void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
+void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
+	struct request	*rq;
 	ide_startstop_t	startstop;
 
 	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
@@ -1426,7 +1580,8 @@
 
 		if ( drive->queue.plugged )	/* paranoia */
 			printk("%s: Huh? nuking plugged queue\n", drive->name);
-		hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
+
+		rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
 		/*
 		 * Some systems have trouble with IDE IRQs arriving while
 		 * the driver is still setting things up.  So, here we disable
@@ -1439,7 +1594,7 @@
 			disable_irq_nosync(hwif->irq);
 		spin_unlock(&io_request_lock);
 		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive);
+		startstop = start_request(drive, rq);
 		spin_lock_irq(&io_request_lock);
 		if (masked_irq && hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
@@ -1867,7 +2022,7 @@
 	ide_drive_t *drive;
 	ide_hwgroup_t *hwgroup;
 	unsigned int p, major, minor;
-	long flags;
+	unsigned long flags;
 
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
@@ -1967,6 +2122,10 @@
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+		if (drive->media == ide_scsi)
+			(void) request_module("ide-scsi");
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
 #endif /* CONFIG_KMOD */
 	while (drive->busy)
@@ -2295,6 +2454,7 @@
 	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
 	hwif->irq = hw->irq;
 	hwif->noprobe = 0;
+	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
 		ide_probe_module();
@@ -2590,6 +2750,61 @@
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
+int ide_reinit_drive (ide_drive_t *drive)
+{
+	switch (drive->media) {
+#ifdef CONFIG_BLK_DEV_IDECD
+		case ide_cdrom:
+		{
+			extern int ide_cdrom_reinit(ide_drive_t *drive);
+			if (ide_cdrom_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+		case ide_disk:
+		{
+			extern int idedisk_reinit(ide_drive_t *drive);
+			if (idedisk_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+		case ide_floppy:
+		{
+			extern int idefloppy_reinit(ide_drive_t *drive);
+			if (idefloppy_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+		case ide_tape:
+		{
+			extern int idetape_reinit(ide_drive_t *drive);
+			if (idetape_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+/*
+ *              {
+ *                      extern int idescsi_reinit(ide_drive_t *drive);
+ *                      if (idescsi_reinit(drive))
+ *                              return 1;
+ *                      break;
+ * }
+ */
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+		default:
+			return 1;
+	}
+	return 0;
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2681,16 +2896,47 @@
 					drive->nice1		<<	IDE_NICE_1		|
 					drive->nice2		<<	IDE_NICE_2,
 					(long *) arg);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+		case HDIO_DRIVE_TASKFILE:
+		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			switch(drive->media) {
+				case ide_disk:
+					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
+#ifdef CONFIG_PKT_TASK_IOCTL
+				case ide_cdrom:
+				case ide_tape:
+				case ide_floppy:
+					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
+				default:
+					return -ENOMSG;
+			}
+#endif /* CONFIG_IDE_TASK_IOCTL */
+
 		case HDIO_DRIVE_CMD:
 		{
 			byte args[4], *argbuf = args;
 			byte xfer_rate = 0;
 			int argsize = 4;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
+			ide_task_t tfargs;
+
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
 			if (NULL == (void *) arg)
 				return ide_do_drive_cmd(drive, &rq, ide_wait);
 			if (copy_from_user(args, (void *)arg, 4))
 				return -EFAULT;
+
+			tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+			tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+			tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+			tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+			tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+			tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+			tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
 			if (args[3]) {
 				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
 				argbuf = kmalloc(argsize, GFP_KERNEL);
@@ -2699,9 +2945,9 @@
 				memcpy(argbuf, args, 4);
 			}
 
-			if (set_transfer(drive, args[0], args[1], args[2])) {
+			if (set_transfer(drive, &tfargs)) {
 				xfer_rate = args[1];
-				if (ide_ata66_check(drive, args[0], args[1], args[2]))
+				if (ide_ata66_check(drive, &tfargs))
 					goto abort;
 			}
 
@@ -2761,7 +3007,24 @@
 			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 		case HDIO_DRIVE_RESET:
+		{
+			unsigned long flags;
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#if 1
+			spin_lock_irqsave(&io_request_lock, flags);
+			if (hwgroup->handler != NULL) {
+				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
+				(void) hwgroup->handler(drive);
+//				hwgroup->handler = NULL;
+//				hwgroup->expiry	= NULL;
+				hwgroup->timer.expires = jiffies + 0;;
+				del_timer(&hwgroup->timer);
+			}
+			spin_unlock_irqrestore(&io_request_lock, flags);
+
+#endif
 			(void) ide_do_reset(drive);
 			if (drive->suspend_reset) {
 /*
@@ -2776,7 +3039,7 @@
 				return ide_revalidate_disk(inode->i_rdev);
 			}
 			return 0;
-
+		}
 		case BLKROSET:
 		case BLKROGET:
 		case BLKFLSBUF:
@@ -2799,7 +3062,7 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(HWIF(drive), arg);
+				HWIF(drive)->busproc(drive, (int)arg);
 			return 0;
 
 		default:
@@ -3466,6 +3729,16 @@
 	return ide_unregister_subdriver(drive);
 }
 
+static int default_standby (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_flushcache (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_end_request(0, HWGROUP(drive));
@@ -3516,7 +3789,7 @@
 	return ide_stopped;
 }
 
-static int default_driver_reinit (ide_drive_t *drive)
+static int default_reinit (ide_drive_t *drive)
 {
 	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
 
@@ -3528,6 +3801,8 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
@@ -3537,7 +3812,7 @@
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
-	if (d->driver_reinit == NULL)	d->driver_reinit = default_driver_reinit;
+	if (d->reinit == NULL)		d->reinit = default_reinit;
 }
 
 ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
@@ -3682,6 +3957,7 @@
 EXPORT_SYMBOL(ide_output_data);
 EXPORT_SYMBOL(atapi_input_bytes);
 EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(drive_is_ready);
 EXPORT_SYMBOL(ide_set_handler);
 EXPORT_SYMBOL(ide_dump_status);
 EXPORT_SYMBOL(ide_error);
@@ -3704,6 +3980,8 @@
 EXPORT_SYMBOL(ide_remove_proc_entries);
 EXPORT_SYMBOL(proc_ide_read_geometry);
 EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL(recreate_proc_ide_device);
+EXPORT_SYMBOL(destroy_proc_ide_device);
 #endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
@@ -3718,6 +3996,54 @@
 
 EXPORT_SYMBOL(system_bus_clock);
 
+EXPORT_SYMBOL(ide_reinit_drive);
+
+static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	switch (event) {
+		case SYS_HALT:
+		case SYS_POWER_OFF:
+		case SYS_RESTART:
+			break;
+		default:
+			return NOTIFY_DONE;
+	}
+
+	printk("flushing ide devices: ");
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (!drive->present)
+				continue;
+
+			/* set the drive to standby */
+			printk("%s ", drive->name);
+			if (event != SYS_RESTART)
+				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
+				continue;
+
+			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+				continue;
+		}
+	}
+	printk("\n");
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ide_notifier = {
+	ide_notify_reboot,
+	NULL,
+	5
+};
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
@@ -3745,6 +4071,7 @@
 			ide_geninit(hwif);
 	}
 
+	register_reboot_notifier(&ide_notifier);
 	return 0;
 }
 
@@ -3777,6 +4104,7 @@
 {
 	int index;
 
+	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
diff -urN linux-2.4.19-pre2/drivers/ide/pdc202xx.c linux-2.4.19-pre3/drivers/ide/pdc202xx.c
--- linux-2.4.19-pre2/drivers/ide/pdc202xx.c	Wed Nov 14 11:44:03 2001
+++ linux-2.4.19-pre3/drivers/ide/pdc202xx.c	Mon Mar 11 14:13:28 2002
@@ -108,7 +108,7 @@
 	u32 bibma  = pci_resource_start(dev, 4);
 	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
 	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
-	u8 hi = 0, lo = 0, invalid_data_set = 0;
+	u8 hi = 0, lo = 0;
 
         /*
          * at that point bibma+0x2 et bibma+0xa are byte registers
@@ -132,11 +132,6 @@
 	pci_read_config_dword(dev, 0x6c, &reg6ch);
 
 	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
-			invalid_data_set = 1;
-			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 			p += sprintf(p, "\n                                PDC20267 Chipset.\n");
 			break;
@@ -180,45 +175,77 @@
 	p += sprintf(p, "           Mode %s                      Mode %s\n",
 		(sc1a & 0x01) ? "MASTER" : "PCI   ",
 		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "                %s                     %s\n",
-			(sc1d & 0x08) ? "Error       " :
-			((sc1d & 0x05) == 0x05) ? "Not My INTR " :
-			(sc1d & 0x04) ? "Interrupting" :
-			(sc1d & 0x02) ? "FIFO Full   " :
-			(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
-			(sc1d & 0x80) ? "Error       " :
-			((sc1d & 0x50) == 0x50) ? "Not My INTR " :
-			(sc1d & 0x40) ? "Interrupting" :
-			(sc1d & 0x20) ? "FIFO Full   " :
-			(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
 	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
 	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
 		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
-			pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
-			pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
-	if (!(invalid_data_set))
-		p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
-			pdc202xx_pio_verbose(reg60h),
-			pdc202xx_pio_verbose(reg64h),
-			pdc202xx_pio_verbose(reg68h),
-			pdc202xx_pio_verbose(reg6ch));
+	p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
 #if 0
 	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
 #endif
-	if (invalid_data_set)
-		p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n");
+	return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+//	u32 bibma = pci_resource_start(dev, 4);
+
+//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+//	u16 reg50h = 0, word88 = 0;
+//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "\n                                PDC20269 TX2 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
+			break;
+default:
+			p += sprintf(p, "\n                                PDC202XX Chipset.\n");
+			break;
+	}
 	return (char *)p;
 }
 
 static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = pdc202xx_info(buffer, bmide_dev);
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p = pdc202xx_info_new(buffer, bmide_dev);
+			break;
+		default:
+			p = pdc202xx_info(buffer, bmide_dev);
+			break;
+	}
 	return p-buffer;	/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -387,9 +414,6 @@
 
 	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
 
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto skip_register_hell;
-
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	pci_read_config_byte(dev, (drive_pci), &AP);
 	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
@@ -432,6 +456,7 @@
 
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+		/* case XFER_UDMA_6: */
 		case XFER_UDMA_5:
 		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
 		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
@@ -477,8 +502,6 @@
 	decode_registers(REG_D, DP);
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-skip_register_hell:
-
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 	err = ide_config_drive_speed(drive, speed);
@@ -494,6 +517,159 @@
 	return err;
 }
 
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	unsigned long indexreg	= (hwif->dma_base + 1);
+	unsigned long datareg	= (hwif->dma_base + 3);
+#else
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
+	unsigned long datareg	= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	byte thold		= 0x10;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+
+	int                     err;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed == XFER_UDMA_2) {
+		OUT_BYTE((thold + adj), indexreg);
+		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
+	}
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x01, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_5:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x02, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_4:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x03, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_3:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x05, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_2:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x2a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x07, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_1:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x3a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0a, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd0, datareg);
+			break;
+		case XFER_UDMA_0:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x4a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0f, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd5, datareg);
+			break;
+		case XFER_MW_DMA_2:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x69, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_MW_DMA_1:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x6b, datareg);
+			OUT_BYTE((0x0f+ adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			break;
+		case XFER_MW_DMA_0:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0xdf, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x5f, datareg);
+			break;
+#else
+	switch (speed) {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x09, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_PIO_3:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x0d, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x35, datareg);
+			break;
+		case XFER_PIO_2:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x26, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x64, datareg);
+			break;
+		case XFER_PIO_1:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x46, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x29, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xa4, datareg);
+			break;
+		case XFER_PIO_0:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0xfb, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x2b, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xac, datareg);
+			break;
+		default:
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+
+	return err;
+}
+
 /*   0    1    2    3    4    5    6   7   8
  * 960, 480, 390, 300, 240, 180, 120, 90, 60
  *           180, 150, 120,  90,  60
@@ -524,18 +700,75 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16   = pci_resource_start(dev, 4);
 	unsigned long dma_base  = hwif->dma_base;
+	unsigned long indexreg	= dma_base + 1;
+	unsigned long datareg	= dma_base + 3;
+	byte iordy		= 0x13;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+	byte cable		= 0;
+	byte jumpbit		= 0;
 	byte unit		= (drive->select.b.unit & 0x01);
-
 	unsigned int		drive_conf;
-	byte			drive_pci;
+	byte			drive_pci = 0;
 	byte			test1, test2, speed = -1;
 	byte			AP;
 	unsigned short		EP;
-	byte CLKSPD		= IN_BYTE(high_16 + 0x11);
-	byte udma_33		= ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+	byte CLKSPD		= 0;
+	byte udma_33		= ultra;
+//	byte udma_33		= ultra ? (IN_BYTE(high_16 + 0x001f) & 1) : 0;
 	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
-	byte udma_100		= (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0;
+	byte udma_100		= 0;
+	byte udma_133		= 0;
+	byte mask		= hwif->channel ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+
+	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
+				   (ultra_66)) ? 1 : 0;
+	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
+				   (ultra_100)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			udma_133 = (udma_66) ? 1 : 0;
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			udma_100 = 1;
+			udma_66 = 1;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			udma_100 = (udma_66) ? 1 : 0;
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		default:
+			udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
+			break;
+	}
 
+	if (!jumpbit)
+		CLKSPD = IN_BYTE(high_16 + 0x11);
 	/*
 	 * Set the control register to use the 66Mhz system
 	 * clock for UDMA 3/4 mode operation. If one drive on
@@ -549,47 +782,52 @@
 	 * parameters.
 	 */
 
-	byte mask		= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto jump_pci_mucking;
-
-	pci_read_config_word(dev, 0x50, &EP);
-
-	if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {
+	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
 #ifdef DEBUG
 		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
 		printk("         Switching to Ultra33 mode.\n");
 #endif /* DEBUG */
 		/* Primary   : zero out second bit */
 		/* Secondary : zero out fourth bit */
-		OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		if (!jumpbit)
+			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+		udma_66 = 0; udma_100 = 0; udma_133 = 0;
 	} else {
-		if ((ultra_66) || (ultra_100)) {
+		if ((ultra_66) || (ultra_100) || (ultra_133)) {
 			/*
 			 * check to make sure drive on same channel
 			 * is u66 capable
 			 */
 			if (hwif->drives[!(drive->dn%2)].id) {
-				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) ||
+				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
+				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
+& 0x0020) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 				} else {
-					OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
 				}
 			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+				if (!jumpbit)
+					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 			}
 		}
 	}
 
+	if (jumpbit) {
+		if (drive->media != ide_disk)	return ide_dma_off_quietly;
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			OUT_BYTE((iordy + adj), indexreg);
+			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+		}
+		goto jumpbit_is_set;
+	}
+
 	switch(drive->dn) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
@@ -640,31 +878,33 @@
 	if (drive->media == ide_disk)	/* PREFETCH_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-jump_pci_mucking:
+jumpbit_is_set:
 
-	if ((id->dma_ultra & 0x0020) && (udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && (udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && (udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && (udma_33))	speed = XFER_UDMA_0;
+	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
+	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
+	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
+	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
 	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
 	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if (id->dma_1word & 0x0004)		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)		speed = XFER_SW_DMA_0;
+	else if ((id->dma_1word & 0x0004)&&(!jumpbit))	speed = XFER_SW_DMA_2;
+	else if ((id->dma_1word & 0x0002)&&(!jumpbit))	speed = XFER_SW_DMA_1;
+	else if ((id->dma_1word & 0x0001)&&(!jumpbit))	speed = XFER_SW_DMA_0;
 	else {
 		/* restore original pci-config space */
-		if (dev->device != PCI_DEVICE_ID_PROMISE_20268)
+		if (!jumpbit)
 			pci_write_config_dword(dev, drive_pci, drive_conf);
 		return ide_dma_off_quietly;
 	}
 
 	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) pdc202xx_tune_chipset(drive, speed);
+	(void) hwif->speedproc(drive, speed);
 
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
 			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
 			((id->dma_1word >> 8) & 7) ? ide_dma_on :
@@ -685,7 +925,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, 1);
 				if ((id->field_valid & 2) &&
@@ -732,16 +972,65 @@
  */
 int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	byte dma_stat = 0, sc1d = 0;
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	unsigned long dma_base	= HWIF(drive)->dma_base;
+	byte dma_stat		= 0;
+	byte sc1d		= 0;
+	byte newchip		= 0;
+	byte clock		= 0;
+	byte hardware48hack	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x00);
+	unsigned long dma_base	= hwif->dma_base;
+
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hardware48hack = 1;
+			clock = IN_BYTE(high_16 + 0x11);
+		default:
+			break;
+	}
 
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_begin:
+			/* Note that this is done *after* the cmd has
+			 * been issued to the drive, as per the BM-IDE spec.
+			 * The Promise Ultra33 doesn't work correctly when
+			 * we do this part before issuing the drive cmd.
+			 */
+			if ((drive->addressing) && (hardware48hack)) {
+				struct request *rq = HWGROUP(drive)->rq;
+				unsigned long word_count = 0;
+
+				outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+				word_count = (rq->nr_sectors << 8);
+				word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
+				outl(word_count, atapi_reg);
+			}
+			break;
+		case ide_dma_end:
+			if ((drive->addressing) && (hardware48hack)) {
+				outl(0, atapi_reg);	/* zero out extra */
+				clock = IN_BYTE(high_16 + 0x11);
+				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+			}
+			break;
 		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			sc1d = inb(high_16 + 0x001d);
+			dma_stat = IN_BYTE(dma_base+2);
+			if (newchip)
+				return (dma_stat & 4) == 4;
+
+			sc1d = IN_BYTE(high_16 + 0x001d);
 			if (HWIF(drive)->channel) {
 				if ((sc1d & 0x50) == 0x50) goto somebody_else;
 				else if ((sc1d & 0x40) == 0x40)
@@ -764,61 +1053,113 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+void pdc202xx_new_reset (ide_drive_t *drive)
+{
+	OUT_BYTE(0x04,IDE_CONTROL_REG);
+	mdelay(1000);
+	OUT_BYTE(0x00,IDE_CONTROL_REG);
+	mdelay(1000);
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
 void pdc202xx_reset (ide_drive_t *drive)
 {
 	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
 
 	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
 	mdelay(100);
 	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
 	mdelay(2000);		/* 2 seconds ?! */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
 }
 
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
 {
-	unsigned long high_16 = pci_resource_start(dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
-	byte primary_mode	= inb(high_16 + 0x001a);
-	byte secondary_mode	= inb(high_16 + 0x001b);
-
-	if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		/*
-		 * software reset -  this is required because the bios
-		 * will set UDMA timing on if the hdd supports it. The
-		 * user may want to turn udma off. A bug in the pdc20262
-		 * is that it cannot handle a downgrade in timing from UDMA
-		 * to DMA. Disk accesses after issuing a set feature command
-		 * will result in errors. A software reset leaves the timing
-		 * registers intact, but resets the drives.
-		 */
-
-		OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-		mdelay(100);
-		OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-		mdelay(2000);	/* 2 seconds ?! */
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+	byte sc1f		= inb(high_16 + 0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		outb(sc1f | 0x08, high_16 + 0x001f);
+	} else {
+		outb(sc1f & ~0x08, high_16 + 0x001f);
 	}
+#endif
+	return 0;
+}
+
+unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
+	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
+	byte newchip		= 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
-	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-		byte irq = 0, irq2 = 0;
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
-		if ((irq != irq2) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20265) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20267) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20268)) {
-			pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
-			printk("%s: pci-config space interrupt mirror fixed.\n", name);
-		}
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);   /* 2 seconds ?! */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			/*
+			 * software reset -  this is required because the bios
+			 * will set UDMA timing on if the hdd supports it. The
+			 * user may want to turn udma off. A bug in the pdc20262
+			 * is that it cannot handle a downgrade in timing from
+			 * UDMA to DMA. Disk accesses after issuing a set
+			 * feature command will result in errors. A software
+			 * reset leaves the timing registers intact,
+			 * but resets the drives.
+			 */
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);	/* 2 seconds ?! */
+		default:
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				byte irq = 0, irq2 = 0;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
+				if (irq != irq2) {
+					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
+					printk("%s: pci-config space interrupt mirror fixed.\n", name);
+				}
+			}
+			break;
 	}
 
+	if (newchip)
+		goto fttk_tx_series;
+
 	printk("%s: (U)DMA Burst Bit %sABLED " \
 		"Primary %s Mode " \
 		"Secondary %s Mode.\n",
@@ -830,8 +1171,8 @@
 #ifdef CONFIG_PDC202XX_BURST
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		outb(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
+		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
+		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
 #endif /* CONFIG_PDC202XX_BURST */
 
@@ -839,18 +1180,20 @@
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
 			name, primary_mode, (primary_mode|1));
-		outb(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
 	}
 
 	if (!(secondary_mode & 1)) {
 		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
 			name, secondary_mode, (secondary_mode|1));
-		outb(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
 #endif /* CONFIG_PDC202XX_MASTER */
 
+fttk_tx_series:
+
 #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!pdc202xx_proc) {
 		pdc202xx_proc = 1;
@@ -866,20 +1209,41 @@
 	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
 	unsigned short CIS;
 
-	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-	return ((CIS & mask) ? 0 : 1);
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
+		default:
+			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+			return (!(CIS & mask));
+	}
 }
 
 void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
-	hwif->tuneproc	= &pdc202xx_tune_drive;
-	hwif->speedproc	= &pdc202xx_tune_chipset;
-	hwif->quirkproc	= &pdc202xx_quirkproc;
-
-	if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		hwif->resetproc	= &pdc202xx_reset;
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			hwif->speedproc = &pdc202xx_new_tune_chipset;
+			hwif->resetproc = &pdc202xx_new_reset;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hwif->busproc   = &pdc202xx_tristate;
+			hwif->resetproc	= &pdc202xx_reset;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			hwif->speedproc = &pdc202xx_tune_chipset;
+		default:
+			break;
 	}
 
 #undef CONFIG_PDC202XX_32_UNMASK
diff -urN linux-2.4.19-pre2/drivers/ide/pdc4030.c linux-2.4.19-pre3/drivers/ide/pdc4030.c
--- linux-2.4.19-pre2/drivers/ide/pdc4030.c	Tue Jul 17 18:53:55 2001
+++ linux-2.4.19-pre3/drivers/ide/pdc4030.c	Mon Mar 11 14:13:28 2002
@@ -89,6 +89,12 @@
 
 #include "pdc4030.h"
 
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  define __TASKFILE__IO
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
 /*
  * promise_selectproc() is invoked by ide.c
  * in preparation for access to the specified drive.
@@ -298,8 +304,6 @@
 	}
 }
 
-
-
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
@@ -495,11 +499,15 @@
  */
 ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
 {
+	ide_startstop_t startstop;
 	unsigned long timeout;
 	byte stat;
 
-	if (rq->cmd == READ) {
-		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
+	switch(rq->cmd) {
+		case READ:
+#ifndef __TASKFILE__IO
+			OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
+#endif
 /*
  * The card's behaviour is odd at this point. If the data is
  * available, DRQ will be true, and no interrupt will be
@@ -510,44 +518,61 @@
  * If neither of these is the case, we wait for up to 50ms (badly I'm
  * afraid!) until one of them is.
  */
-		timeout = jiffies + HZ/20; /* 50ms wait */
-		do {
-			stat=GET_STAT();
-			if (stat & DRQ_STAT) {
-				udelay(1);
-				return promise_read_intr(drive);
-			}
-			if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
+			timeout = jiffies + HZ/20; /* 50ms wait */
+			do {
+				stat=GET_STAT();
+				if (stat & DRQ_STAT) {
+					udelay(1);
+					return promise_read_intr(drive);
+				}
+				if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
 #ifdef DEBUG_READ
-				printk(KERN_DEBUG "%s: read: waiting for "
-				                  "interrupt\n", drive->name);
+	printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name);
 #endif
-				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-				return ide_started;
-			}
-			udelay(1);
-		} while (time_before(jiffies, timeout));
-
-		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
-			drive->name);
-		return ide_stopped;
-	} else if (rq->cmd == WRITE) {
-		ide_startstop_t startstop;
-		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing "
-			       "PROMISE_WRITE\n", drive->name);
-			return startstop;
-	    	}
-		if (!drive->unmask)
-			__cli();	/* local CPU only */
-		HWGROUP(drive)->wrq = *rq; /* scratchpad */
-		return promise_write(drive);
+					ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
+					return ide_started;
+				}
+				udelay(1);
+			} while (time_before(jiffies, timeout));
 
-	} else {
-		printk("KERN_WARNING %s: bad command: %d\n",
-		       drive->name, rq->cmd);
-		ide_end_request(0, HWGROUP(drive));
-		return ide_stopped;
+			printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name);
+			return ide_stopped;
+		case WRITE:
+#ifndef __TASKFILE__IO
+			OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif
+			if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+				printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
+				return startstop;
+		    	}
+			if (!drive->unmask)
+				__cli();	/* local CPU only */
+			HWGROUP(drive)->wrq = *rq; /* scratchpad */
+			return promise_write(drive);
+		default:
+			printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd);
+			ide_end_request(0, HWGROUP(drive));
+			return ide_stopped;
 	}
 }
+
+#ifdef __TASKFILE__IO
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr taskfile;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	do_taskfile(drive, &taskfile, NULL, NULL);
+	return do_pdc4030_io(drive, rq);
+}
+#endif
+
diff -urN linux-2.4.19-pre2/drivers/ide/piix.c linux-2.4.19-pre3/drivers/ide/piix.c
--- linux-2.4.19-pre2/drivers/ide/piix.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/ide/piix.c	Mon Mar 11 14:13:28 2002
@@ -425,7 +425,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = piix_config_drive_for_dma(drive);
 				if ((id->field_valid & 2) &&
diff -urN linux-2.4.19-pre2/drivers/ide/qd65xx.c linux-2.4.19-pre3/drivers/ide/qd65xx.c
--- linux-2.4.19-pre2/drivers/ide/qd65xx.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/ide/qd65xx.c	Mon Mar 11 14:13:28 2002
@@ -1,14 +1,15 @@
 /*
- *  linux/drivers/ide/qd65xx.c		Version 0.06	Aug 3, 2000
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
  *
- *  Copyright (C) 1996-2000  Linus Torvalds & author (see below)
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
  */
 
 /*
  *  Version 0.03	Cleaned auto-tune, added probe
  *  Version 0.04	Added second channel tuning
  *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	added dos driver's list
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
  *
  * QDI QD6500/QD6580 EIDE controller fast support
  *
@@ -67,6 +68,7 @@
  *        qd6500: 1100
  *        qd6580: either 1010 or 0101
  *
+ *
  * base+0x02: Timer2 (qd6580 only)
  *
  *
@@ -137,12 +139,12 @@
 {
 	byte active_cycle,recovery_cycle;
 
-	if (system_bus_clock()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	if (ide_system_bus_speed()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
 	} else {
-		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
 	}
 
 	return((recovery_cycle<<4) | 0x08 | active_cycle);
@@ -156,8 +158,8 @@
 
 static byte qd6580_compute_timing (int active_time, int recovery_time)
 {
-	byte active_cycle   = 17-IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
+	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
 
 	return((recovery_cycle<<4) | active_cycle);
 }
@@ -427,7 +429,8 @@
 				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
 
 				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA;
+					ide_hwifs[i].drives[j].drive_data =
+					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
 					ide_hwifs[i].drives[j].io_32bit = 1;
 				}
 			}
diff -urN linux-2.4.19-pre2/drivers/ide/qd65xx.h linux-2.4.19-pre3/drivers/ide/qd65xx.h
--- linux-2.4.19-pre2/drivers/ide/qd65xx.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/ide/qd65xx.h	Mon Mar 11 14:13:28 2002
@@ -29,7 +29,7 @@
 
 #define QD_CONTR_SEC_DISABLED	0x01
 
-#define QD_ID3			(config & QD_CONFIG_ID3)
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
 
 #define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
 #define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
@@ -39,6 +39,7 @@
 
 #define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
 #define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
 #define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
 
 #define QD_TESTVAL		0x19	/* safe value */
diff -urN linux-2.4.19-pre2/drivers/ide/serverworks.c linux-2.4.19-pre3/drivers/ide/serverworks.c
--- linux-2.4.19-pre2/drivers/ide/serverworks.c	Sun Sep  9 10:43:02 2001
+++ linux-2.4.19-pre3/drivers/ide/serverworks.c	Mon Mar 11 14:13:28 2002
@@ -1,16 +1,26 @@
 /*
- * linux/drivers/ide/serverworks.c		Version 0.2	17 Oct 2000
+ * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
  *
- *  Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
- *  May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
  *
- *  interface borrowed from alim15x3.c:
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
  *
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
  *
- *  IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
  *
  * here's the default lspci:
  *
@@ -83,15 +93,15 @@
 
 #include "ide_modes.h"
 
-#define SVWKS_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS	1
+#undef SVWKS_DEBUG_DRIVE_INFO
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
 static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@
 	u32 bibma = pci_resource_start(bmide_dev, 4);
 	u32 reg40, reg44;
 	u16 reg48, reg56;
-	u8  c0 = 0, c1 = 0, reg54;
+	u8  reg54, c0=0, c1=0;
 
 	pci_read_config_dword(bmide_dev, 0x40, &reg40);
 	pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@
 
 	switch(bmide_dev->device) {
 		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                                ServerWorks CSB5 Chipset.\n");
+			p += sprintf(p, "\n                            "
+				     "ServerWorks CSB5 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4:
-			p += sprintf(p, "\n                                ServerWorks OSB4 Chipset.\n");
+		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+			p += sprintf(p, "\n                            "
+				     "ServerWorks OSB4 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
 		default:
-			p += sprintf(p, "\n                                ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+			p += sprintf(p, "\n                            "
+				     "ServerWorks %04x Chipset (rev %02x)\n",
+				     bmide_dev->device, svwks_revision);
 			break;
 	}
 
 	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-#if 0
-	p += sprintf(p, "                                     : %s\n", "str");
-#endif
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
 	p += sprintf(p, "                %sabled                         %sabled\n",
 			(c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@
 				((reg44&0x00210000)==0x00210000)?"1":
 				((reg44&0x00770000)==0x00770000)?"0":
 				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
 		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
 			((reg40&0x00002000)==0x00002000)?"4":
 				((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@
 }
 #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 
 byte svwks_proc = 0;
 
@@ -292,6 +301,7 @@
 			pio_timing |= pio_modes[speed - XFER_PIO_0];
 			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
 			break;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[2];
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
 			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
 #endif
@@ -322,9 +332,9 @@
 		drive->name, ultra_timing, dma_timing, pio_timing);
 #endif
 
-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
@@ -338,11 +348,10 @@
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
 	
-	if (speed > XFER_PIO_4) {
+	if (speed > XFER_PIO_4)
 		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
+	else
 		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte			timing, speed, pio;
+	byte timing, speed, pio;
 
 	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
 
 	if (xfer_pio> 4)
 		xfer_pio = 0;
 
-	if (drive->id->eide_pio_iordy > 0) {
+	if (drive->id->eide_pio_iordy > 0)
 		for (xfer_pio = 5;
 			xfer_pio>0 &&
 			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
 			xfer_pio--);
-	} else {
+	else
 		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
 			   (drive->id->eide_pio_modes & 2) ? 0x04 :
 			   (drive->id->eide_pio_modes & 1) ? 0x03 :
 			   (drive->id->tPIO & 2) ? 0x02 :
 			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
 
 	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
@@ -407,12 +415,10 @@
 {
 	struct hd_driveid *id	= drive->id;
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte			speed;
-
-	int ultra66		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	/* need specs to figure out if osb4 is capable of ata/66/100 */
-	int ultra100		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	byte udma_66	= eighty_ninty_three(drive);
+	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
+	byte speed;
 
 	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
 		speed = XFER_UDMA_5;
@@ -458,7 +464,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) &&
@@ -499,7 +505,41 @@
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
-		default :
+		case ide_dma_end:
+		{
+			ide_hwif_t *hwif		= HWIF(drive);
+			unsigned long dma_base		= hwif->dma_base;
+	
+			if(inb(dma_base+0x02)&1)
+			{
+#if 0		
+				int i;
+				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
+				for(i=0;i<10;i++)
+				{
+					if(!(inb(dma_base+0x02)&1))
+					{
+						printk(KERN_ERR "OSB4 now finished.\n");
+						break;
+					}
+					udelay(5);
+				}
+#endif		
+				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+#if 0		
+				/* Panic might sys_sync -> death by corrupt disk */
+				panic("OSB4: continuing might cause disk corruption.\n");
+#else
+				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+				while(1)
+					cpu_relax();
+#endif				
+			}
+			/* and drop through */
+		}
+		default:
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +549,43 @@
 
 unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
 {
-	unsigned int reg64;
+	unsigned int reg;
+	byte btr;
 
+	/* save revision id to determine DMA capability */
 	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
-		pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
-		printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
 
-//		reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-//		reg64 |= 0x00008000;
-//#endif
-	/* Assume the APIC was set up properly by the BIOS for now . If it
-	   wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
-	   APIC enable, routing and decode */
-	   
-		reg64 &= ~0x00002000;	
-		pci_write_config_dword(isa_dev, 0x64, reg64);
+	/* setup CSB5 : South Bridge and IDE */
+	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 *      00 : legacy
+		 *      01 : udma2
+		 *      10 : udma2/udma4
+		 *      11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
 	}
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!svwks_proc) {
@@ -551,26 +604,46 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-
 static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL        &&
-	    dev->vendor           == PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device           == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
 		return ((1 << (hwif->channel + 14)) &
 			dev->subsystem_device) ? 1 : 0;
-
 	return 0;
+}
 
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
 }
 
 unsigned int __init ata66_svwks (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Dell PowerEdge */
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 		return ata66_svwks_dell (hwif);
-	
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
 	return 0;
 }
 
@@ -586,12 +659,12 @@
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
-	return;
 #else /* CONFIG_BLK_DEV_IDEDMA */
-
 	if (hwif->dma_base) {
+#ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
 			hwif->autodma = 1;
+#endif	
 		hwif->dmaproc = &svwks_dmaproc;
 	} else {
 		hwif->autodma = 0;
diff -urN linux-2.4.19-pre2/drivers/ide/sis5513.c linux-2.4.19-pre3/drivers/ide/sis5513.c
--- linux-2.4.19-pre2/drivers/ide/sis5513.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/ide/sis5513.c	Mon Mar 11 14:13:28 2002
@@ -1,11 +1,28 @@
 /*
- * linux/drivers/ide/sis5513.c		Version 0.11	June 9, 2000
+ * linux/drivers/ide/sis5513.c		Version 0.13	February 14, 2002
  *
  * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
  * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to SIS Taiwan for direct support and hardware.
- * Tested and designed on the SiS620/5513 chipset.
+ * Thanks to Daniela Engert for ATA100 support advice.
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 design from specs
+ */
+
+/*
+ * TODO:
+ *	- Are there pre-ATA_16 SiS chips ? -> tune init code for them
+ *	  or remove ATA_00 defines
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Get ATA-133 datasheets, implement ATA-133 init code.
+ *	- Check latency timer init correctness.
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
  */
 
 #include <linux/config.h>
@@ -28,88 +45,181 @@
 
 #include "ide_modes.h"
 
+#define DEBUG
+/* if BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
 #define DISPLAY_SIS_TIMINGS
-#define SIS5513_DEBUG_DRIVE_INFO	0
 
-static struct pci_dev *host_dev = NULL;
+/* Miscellaneaous flags */
+#define SIS5513_LATENCY		0x01
+/* ATA transfer mode capabilities */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100		0x04
+#define ATA_133		0x05
+
+static unsigned char dma_capability = 0x00;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers 0x00 -> 0x58
+   Fewer might be used depending on the actual chipset */
+static unsigned char ide_regs_copy[] = {
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0,
+	0x0, 0x0, 0x0, 0x0
+};
+
+static byte sis5513_max_config_register(void) {
+	switch(dma_capability) {
+		case ATA_00:
+		case ATA_16:	return 0x4f;
+		case ATA_33:	return 0x52;
+		case ATA_66:
+		case ATA_100:
+		case ATA_133:
+		default:	return 0x57;
+	}
+}
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	byte reg_val;
+	byte changed=0;
+	byte max = sis5513_max_config_register();
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=max; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%0#x: %0#x -> %0#x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
+
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+	byte max = sis5513_max_config_register();
+
+	for(i=0; i<=max; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print a register */
+static void sis5513_print_register(int reg) {
+	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
+}
+
+/* Print valuable registers (for ATA100) */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i;
+	byte max = sis5513_max_config_register();
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+	printk("SIS5513 dump:");
+	for(i=0x00; i<0x40; i++) {
+		if ((i % 0x10)==0) printk("\n             ");
+		sis5513_print_register(i);
+	}
+	for(; i<49; i++) {
+		sis5513_print_register(i);
+	}
+	printk("\n             ");
+
+	for(; i<=max; i++) {
+		sis5513_print_register(i);
+	}
+	printk("\n");
+}
+#endif
 
-#define SIS5513_FLAG_ATA_00		0x00000000
-#define SIS5513_FLAG_ATA_16		0x00000001
-#define SIS5513_FLAG_ATA_33		0x00000002
-#define SIS5513_FLAG_ATA_66		0x00000004
-#define SIS5513_FLAG_LATENCY		0x00000010
 
+/*
+ * Devices supported
+ */
 static const struct {
 	const char *name;
 	unsigned short host_id;
-	unsigned int flags;
+	unsigned char dma_capability;
+	unsigned char flags;
 } SiSHostChipInfo[] = {
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	SIS5513_FLAG_ATA_66, },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	SIS5513_FLAG_ATA_66, },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS645",	PCI_DEVICE_ID_SI_645,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS650",	PCI_DEVICE_ID_SI_650,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS745",	PCI_DEVICE_ID_SI_745,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS750",	PCI_DEVICE_ID_SI_750,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	SIS5513_FLAG_ATA_33, },
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	SIS5513_FLAG_ATA_16, },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
 };
 
-#if 0
-
-static struct _pio_mode_mapping {
-	byte data_active;
-	byte recovery;
-	byte pio_mode;
-} pio_mode_mapping[] = {
-	{ 8, 12, 0 },
-	{ 6,  7, 1 },
-	{ 4,  4, 2 },
-	{ 3,  3, 3 },
-	{ 3,  1, 4 }
-};
-
-static struct _dma_mode_mapping {
-	byte data_active;
-	byte recovery;
-	byte dma_mode;
-} dma_mode_mapping[] = {
-	{ 8, 8, 0 },
-	{ 3, 2, 1 },
-	{ 3, 1, 2 }
+/* Cycle time bits and values vary accross chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by dma_capability and (dma_mode - XFER_UDMA_0) */
+static byte cycle_time_offset[] = {0,0,5,4,0,0};
+static byte cycle_time_range[] = {0,0,2,3,4,4};
+static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0},
+	{7,5,3,2,1,0},
+	{11,7,5,4,2,1},
+	{0,0,0,0,0,0} /* not yet known, ask SiS */
 };
 
-static struct _udma_mode_mapping {
-	byte cycle_time;
-	char * udma_mode;
-} udma_mode_mapping[] = {
-	{ 8, "Mode 0" },
-	{ 6, "Mode 1" },
-	{ 4, "Mode 2" }, 
-	{ 3, "Mode 3" },
-	{ 2, "Mode 4" },
-	{ 0, "Mode 5" }
-};
+static struct pci_dev *host_dev = NULL;
 
-static __inline__ char * find_udma_mode (byte cycle_time)
-{
-	int n;
-	
-	for (n = 0; n <= 4; n++)
-		if (udma_mode_mapping[n].cycle_time <= cycle_time)
-			return udma_mode_mapping[n].udma_mode;
-	return udma_mode_mapping[4].udma_mode;
-}
-#endif
 
+/*
+ * Printing configuration
+ */
 #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -118,12 +228,12 @@
 extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 static struct pci_dev *bmide_dev;
 
-static char *cable_type[] = {
+static char* cable_type[] = {
 	"80 pins",
 	"40 pins"
 };
 
-static char *recovery_time [] ={
+static char* recovery_time[] ={
 	"12 PCICLK", "1 PCICLK",
 	"2 PCICLK", "3 PCICLK",
 	"4 PCICLK", "5 PCICLCK",
@@ -134,101 +244,179 @@
 	"15 PCICLK", "15 PCICLK"
 };
 
-static char * cycle_time [] = {
-	"2 CLK", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK"
-};
-
-static char * active_time [] = {
+static char* active_time[] = {
 	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "2 PCICLK",
+	"2 PCICLK", "3 PCICLK",
 	"4 PCICLK", "5 PCICLK",
 	"6 PCICLK", "12 PCICLK"
 };
 
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"Reserved", "Reserved",
+	"Reserved", "Reserved"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, byte pos)
+{
+	byte reg00, reg01, reg10, reg11; /* timing registers */
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+
+	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+
+/* UDMA */
+	if (dma_capability >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(dma_capability) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(dma_capability) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(dma_capability) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(dma_capability) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
 static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	int rc;
 	char *p = buffer;
-	byte reg,reg1;
+	byte reg;
 	u16 reg2, reg3;
 
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(dma_capability) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133:
+		default: p+= sprintf(p, "Ultra 133+"); break;
+	}
+	p += sprintf(p, " chipset\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	rc = pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n",
-		     (reg & 0x02) ? "On" : "Off",
-		     (reg & 0x04) ? "On" : "Off");
-		     
-	rc = pci_read_config_byte(bmide_dev, 0x09, &reg);
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	p += sprintf(p, "Channel Status: ");
+	if (dma_capability < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
 	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
 		     (reg & 0x01) ? "Native" : "Compatible",
 		     (reg & 0x04) ? "Native" : "Compatible");
-		     	     
-	rc = pci_read_config_byte(bmide_dev, 0x48, &reg);
-	p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-		     (reg & 0x10) ? cable_type[1] : cable_type[0],
-		     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-		     
-	rc = pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	rc = pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drive 0:        Postwrite %s \t \t Postwrite %s\n",
-		     (reg & 0x10) ? "Enabled" : "Disabled",
-		     (reg & 0x40) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg & 0x01) ? "Enabled" : "Disabled",
-		     (reg & 0x04) ? "Enabled" : "Disabled");
-		          
-	rc = pci_read_config_byte(bmide_dev, 0x41, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x45, &reg1);
-	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-		     (reg & 0x80)  ? "Enabled" : "Disabled",
-		     (reg1 & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
-		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
-	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
-		     active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
-
-	rc = pci_read_config_byte(bmide_dev, 0x40, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x44, &reg1);
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
 
+/* 80-pin cable ? */
+	if (dma_capability > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
 
-	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
-	p += sprintf(p, "Drive 1:        Postwrite %s \t \t Postwrite %s\n",
-		     (reg & 0x20) ? "Enabled" : "Disabled",
-		     (reg & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg & 0x02) ? "Enabled" : "Disabled",
-		     (reg & 0x08) ? "Enabled" : "Disabled");
+/* Prefetch Count */
+	pci_read_config_word(bmide_dev, 0x4c, &reg2);
+	pci_read_config_word(bmide_dev, 0x4e, &reg3);
+	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+		     reg2, reg3);
 
-	rc = pci_read_config_byte(bmide_dev, 0x43, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x47, &reg1);
-	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-		     (reg & 0x80)  ? "Enabled" : "Disabled",
-		     (reg1 & 0x80) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
-		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
-	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
-		     active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
 
-	rc = pci_read_config_byte(bmide_dev, 0x42, &reg);
-	rc = pci_read_config_byte(bmide_dev, 0x46, &reg1);
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
 	return p-buffer;
 }
 #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+
 byte sis_proc = 0;
 extern char *ide_xfer_verbose (byte xfer_rate);
 
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
 static void config_drive_art_rwp (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -237,14 +425,24 @@
 	byte reg4bh		= 0;
 	byte rw_prefetch	= (0x11 << drive->dn);
 
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
 	if (drive->media != ide_disk)
 		return;
-	
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
 	if ((reg4bh & rw_prefetch) != rw_prefetch)
 		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
 }
 
+
+/* Set per-drive active and recovery time */
 static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -255,6 +453,10 @@
 	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
 
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
 	config_drive_art_rwp(drive);
 	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
 
@@ -263,8 +465,8 @@
 
 	if (drive->id->eide_pio_iordy > 0) {
 		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
 			xfer_pio--);
 	} else {
 		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
@@ -274,14 +476,10 @@
 
 	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
-/*
- *               Mode 0       Mode 1     Mode 2     Mode 3     Mode 4
- * Active time    8T (240ns)  6T (180ns) 4T (120ns) 3T  (90ns) 3T  (90ns)
- * 0x41 2:0 bits  000          110        100        011        011
- * Recovery time 12T (360ns)  7T (210ns) 4T (120ns) 3T  (90ns) 1T  (30ns)
- * 0x40 3:0 bits 0000         0111       0100       0011       0001
- * Cycle time    20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
- */
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
 
 	switch(drive->dn) {
 		case 0:		drive_pci = 0x40; break;
@@ -291,31 +489,43 @@
 		default:	return;
 	}
 
-	pci_read_config_byte(dev, drive_pci, &test1);
-	pci_read_config_byte(dev, drive_pci|0x01, &test2);
-
-	/*
-	 * Do a blanket clear of active and recovery timings.
-	 */
-
-	test1 &= ~0x07;
-	test2 &= ~0x0F;
-
-	switch(timing) {
-		case 4:		test1 |= 0x01; test2 |= 0x03; break;
-		case 3:		test1 |= 0x03; test2 |= 0x03; break;
-		case 2:		test1 |= 0x04; test2 |= 0x04; break;
-		case 1:		test1 |= 0x07; test2 |= 0x06; break;
-		default:	break;
+	/* register layout changed with ATA100 chips */
+	if (dma_capability < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else {
+		switch(timing) { /*   active  recovery
+					  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
 	}
 
-	pci_write_config_byte(dev, drive_pci, test1);
-	pci_write_config_byte(dev, drive_pci|0x01, test2);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
 }
 
 static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
 {
-	int err;
 	byte speed;
 
 	switch(pio) {
@@ -328,8 +538,7 @@
 
 	config_art_rwp_pio(drive, pio);
 	drive->current_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	return err;
+	return ide_config_drive_speed(drive, speed);
 }
 
 static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
@@ -337,82 +546,71 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 
-	byte			drive_pci, test1, test2;
-	byte			unmask, four_two, mask = 0;
-
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				unmask   = 0xF0;
-				four_two = 0x01;
-				break;
-			default:
-				unmask   = 0xE0;
-				four_two = 0x00;
-				break;
-		}
-	} else {
-		unmask   = 0xE0;
-		four_two = 0x00;
-	}
+	byte			drive_pci, reg;
 
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, speed);
+#endif
 	switch(drive->dn) {
-		case 0:		drive_pci = 0x40;break;
-		case 1:		drive_pci = 0x42;break;
-		case 2:		drive_pci = 0x44;break;
-		case 3:		drive_pci = 0x46;break;
+		case 0:		drive_pci = 0x40; break;
+		case 1:		drive_pci = 0x42; break;
+		case 2:		drive_pci = 0x44; break;
+		case 3:		drive_pci = 0x46; break;
 		default:	return ide_dma_off;
 	}
 
-	pci_read_config_byte(dev, drive_pci, &test1);
-	pci_read_config_byte(dev, drive_pci|0x01, &test2);
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
+#endif
+	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
+#endif
 
-	if ((speed <= XFER_MW_DMA_2) && (test2 & 0x80)) {
-		pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80);
-		pci_read_config_byte(dev, drive_pci|0x01, &test2);
-	} else {
-		pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
+	pci_read_config_byte(dev, drive_pci+1, &reg);
+	/* Disable UDMA bit for non UDMA modes on UDMA chips */
+	if ((speed < XFER_UDMA_0) && (dma_capability > ATA_16)) {
+		reg &= 0x7F;
+		pci_write_config_byte(dev, drive_pci+1, reg);
 	}
 
+	/* Config chip for mode */
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5: mask = 0x80; break;
-		case XFER_UDMA_4: mask = 0x90; break;
-		case XFER_UDMA_3: mask = 0xA0; break;
-		case XFER_UDMA_2: mask = (four_two) ? 0xB0 : 0xA0; break;
-		case XFER_UDMA_1: mask = (four_two) ? 0xD0 : 0xC0; break;
-		case XFER_UDMA_0: mask = unmask; break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			/* clean reg cycle time bits */
+			reg &= ~((0xFF >> (8 - cycle_time_range[dma_capability]))
+				 << cycle_time_offset[dma_capability]);
+			/* set reg cycle time bits */
+			reg |= cycle_time_value[dma_capability-ATA_00][speed-XFER_UDMA_0]
+				<< cycle_time_offset[dma_capability];
+			pci_write_config_byte(dev, drive_pci+1, reg);
+			break;
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_MW_DMA_0:
 		case XFER_SW_DMA_2:
 		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0: break;
+		case XFER_SW_DMA_0:
+			break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
 		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
 		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
 		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
 		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
 	}
-
-	if (speed > XFER_MW_DMA_2)
-		pci_write_config_byte(dev, drive_pci|0x01, test2|mask);
-
 	drive->current_speed = speed;
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
 	return ((int) ide_config_drive_speed(drive, speed));
 }
 
@@ -430,47 +628,27 @@
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
 
-	byte			four_two = 0, speed = 0;
-	int			err;
+	byte			speed = 0;
 
 	byte unit		= (drive->select.b.unit & 0x01);
 	byte udma_66		= eighty_ninty_three(drive);
-	byte ultra_100		= 0;
 
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				ultra_100 = 1;
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-				four_two = 0x01;
-				break;
-			default:
-				four_two = 0x00; break;
-		}
-	}
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
+	       drive->dn, ultra);
+#endif
 
-	if ((id->dma_ultra & 0x0020) && (ultra) && (udma_66) && (four_two) && (ultra_100))
+	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (dma_capability >= ATA_100))
 		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two))
+	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (dma_capability >= ATA_66))
 		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two))
+	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (dma_capability >= ATA_66))
 		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && (ultra))
+	else if ((id->dma_ultra & 0x0004) && ultra && (dma_capability >= ATA_33))
 		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && (ultra))
+	else if ((id->dma_ultra & 0x0002) && ultra && (dma_capability >= ATA_33))
 		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && (ultra))
+	else if ((id->dma_ultra & 0x0001) && ultra && (dma_capability >= ATA_33))
 		speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)
 		speed = XFER_MW_DMA_2;
@@ -489,11 +667,7 @@
 
 	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
 
-	err = sis5513_tune_chipset(drive, speed);
-
-#if SIS5513_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SIS5513_DEBUG_DRIVE_INFO */
+	sis5513_tune_chipset(drive, speed);
 
 	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -550,9 +724,7 @@
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
-/*
- * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
+/* initiates/aborts (U)DMA read/write operations on a drive. */
 int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	switch (func) {
@@ -567,15 +739,18 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+/* Chip detection and general config */
 unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
 	int i = 0;
-	byte latency = 0;
 
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+#ifdef DEBUG
+	sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
 
-	for (i = 0; i < ARRAY_SIZE (SiSHostChipInfo) && !host_dev; i++) {
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
 		host = pci_find_device (PCI_VENDOR_ID_SI,
 					SiSHostChipInfo[i].host_id,
 					NULL);
@@ -583,30 +758,66 @@
 			continue;
 
 		host_dev = host;
+		dma_capability = SiSHostChipInfo[i].dma_capability;
 		printk(SiSHostChipInfo[i].name);
 		printk("\n");
-		if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) {
-			if (latency != 0x10)
-				pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			byte latency = (dma_capability == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
 		}
 	}
 
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compabitility mode only
+	   2/ tell old chips to allow per drive IDE timings */
 	if (host_dev) {
-		byte reg52h = 0;
-
-		pci_read_config_byte(dev, 0x52, &reg52h);
-		if (!(reg52h & 0x04)) {
-			/* set IDE controller to operate in Compabitility mode only */
-			pci_write_config_byte(dev, 0x52, reg52h|0x04);
+		byte reg;
+		switch(dma_capability) {
+			case ATA_133:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
 		}
+
 #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
 		if (!sis_proc) {
 			sis_proc = 1;
 			bmide_dev = dev;
 			sis_display_info = &sis_get_info;
 		}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif
 	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
 	return 0;
 }
 
@@ -616,27 +827,10 @@
 	byte mask = hwif->channel ? 0x20 : 0x10;
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
 
-	if (host_dev) {
-		switch(host_dev->device) {
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-				ata66 = (reg48h & mask) ? 0 : 1;
-			default:
-				break;
-		}
+	if (dma_capability >= ATA_66) {
+		ata66 = (reg48h & mask) ? 0 : 1;
 	}
-        return (ata66);
+        return ata66;
 }
 
 void __init ide_init_sis5513 (ide_hwif_t *hwif)
@@ -651,33 +845,16 @@
 		return;
 
 	if (host_dev) {
-		switch(host_dev->device) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-			case PCI_DEVICE_ID_SI_530:
-			case PCI_DEVICE_ID_SI_540:
-			case PCI_DEVICE_ID_SI_620:
-			case PCI_DEVICE_ID_SI_630:
-			case PCI_DEVICE_ID_SI_635:
-			case PCI_DEVICE_ID_SI_640:
-			case PCI_DEVICE_ID_SI_645:
-			case PCI_DEVICE_ID_SI_650:
-			case PCI_DEVICE_ID_SI_730:
-			case PCI_DEVICE_ID_SI_735:
-			case PCI_DEVICE_ID_SI_740:
-			case PCI_DEVICE_ID_SI_745:
-			case PCI_DEVICE_ID_SI_750:
-			case PCI_DEVICE_ID_SI_5600:
-			case PCI_DEVICE_ID_SI_5597:
-			case PCI_DEVICE_ID_SI_5591:
-				if (!noautodma)
-					hwif->autodma = 1;
-				hwif->dmaproc = &sis5513_dmaproc;
-				break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-			default:
-				hwif->autodma = 0;
-				break;
+		if (dma_capability > ATA_16) {
+			hwif->autodma = noautodma ? 0 : 1;
+			hwif->dmaproc = &sis5513_dmaproc;
+		} else {
+#endif
+			hwif->autodma = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
 		}
+#endif
 	}
 	return;
 }
diff -urN linux-2.4.19-pre2/drivers/ide/slc90e66.c linux-2.4.19-pre3/drivers/ide/slc90e66.c
--- linux-2.4.19-pre2/drivers/ide/slc90e66.c	Sun Jul 15 16:22:23 2001
+++ linux-2.4.19-pre3/drivers/ide/slc90e66.c	Mon Mar 11 14:13:28 2002
@@ -86,8 +86,13 @@
          * at that point bibma+0x2 et bibma+0xa are byte registers
          * to investigate:
          */
+#ifdef __mips__	/* only for mips? */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+#else
 	c0 = inb_p((unsigned short)bibma + 0x02);
 	c1 = inb_p((unsigned short)bibma + 0x0a);
+#endif
 
 	p += sprintf(p, "                                SLC90E66 Chipset.\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
@@ -253,7 +258,9 @@
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:	break;
+#if 0	/* allow PIO modes */
 		default:		return -1;
+#endif
 	}
 
 	if (speed >= XFER_UDMA_0) {
@@ -291,6 +298,13 @@
 	byte speed		= 0;
 	byte udma_66		= eighty_ninty_three(drive);
 
+#if 1 /* allow PIO modes */
+	if (!HWIF(drive)->autodma) {
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+		(void) slc90e66_tune_chipset(drive, speed);
+		return ((int) ide_dma_off_quietly);
+	}
+#endif
 	if ((id->dma_ultra & 0x0010) && (ultra)) {
 		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
diff -urN linux-2.4.19-pre2/drivers/isdn/act2000/act2000_isa.c linux-2.4.19-pre3/drivers/isdn/act2000/act2000_isa.c
--- linux-2.4.19-pre2/drivers/isdn/act2000/act2000_isa.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/isdn/act2000/act2000_isa.c	Mon Mar 11 14:13:28 2002
@@ -178,7 +178,8 @@
                 card->flags &= ~ACT2000_FLAGS_PVALID;
         }
         if (!check_region(portbase, ISA_REGION)) {
-                request_region(portbase, ACT2000_PORTLEN, card->regname);
+                if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
+			return -EIO;
                 card->port = portbase;
                 card->flags |= ACT2000_FLAGS_PVALID;
                 return 0;
diff -urN linux-2.4.19-pre2/drivers/isdn/eicon/eicon_mod.c linux-2.4.19-pre3/drivers/isdn/eicon/eicon_mod.c
--- linux-2.4.19-pre2/drivers/isdn/eicon/eicon_mod.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/isdn/eicon/eicon_mod.c	Mon Mar 11 14:13:28 2002
@@ -665,8 +665,11 @@
 			else
 				cnt = skb->len;
 
-			if (user)
+			if (user) {
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				copy_to_user(p, skb->data, cnt);
+				spin_lock_irqsave(&eicon_lock, flags);
+			}
 			else
 				memcpy(p, skb->data, cnt);
 
diff -urN linux-2.4.19-pre2/drivers/media/video/w9966.c linux-2.4.19-pre3/drivers/media/video/w9966.c
--- linux-2.4.19-pre2/drivers/media/video/w9966.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/media/video/w9966.c	Mon Mar 11 14:13:28 2002
@@ -19,18 +19,25 @@
 */
 /*
 	Supported devices:
-	  * Lifeview FlyCam Supra (using the Philips saa7111a chip)
+	  * Lifeview Flycam Supra (Philips saa7111a chip)
+
+	  * Mikrotek Eyestar2 (Sanyo lc99053 chip)
+	    Very rudimentary support, total lack of ccd-control chip settings.
+	    Only green video data and no image properties (brightness, etc..)
+	    If anyone can parse the Japanese data-sheet for the Sanyo lc99053
+	    chip, feel free to help.
+	    <http://service.semic.sanyo.co.jp/semi/ds_pdf_j/LC99053.pdf>
+	    Thanks to Steven Griffiths <steve@sgriff.com> and
+	    James Murray <jsm@jsm-net.demon.co.uk> for testing.
 
 	Todo:
-	  * Add a working EPP mode
-	  * Support other ccd-control chips than the saa7111
-	    (what combinations exists?)
+	  * Add a working EPP mode (Is this a parport or a w9966 issue?)
 	  * Add proper probing. IEEE1284 probing of w9966 chips haven't
 	    worked since parport drivers changed in 2.4.x.
-	  * Probe for onboard SRAM, port directions etc. (if possible)
+	  * Probe for onboard SRAM, port directions etc. (possible?)
 
 	Changes:
-	
+
 	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
 			and owner support for newer module locks
 */
@@ -43,112 +50,155 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 
-//#define DEBUG				// Undef me for production
+//#define DEBUG				// Uncomment for debug output.
 
 #ifdef DEBUG
-#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a)
+#   define DPRINTF(f, a...)						\
+	do {								\
+		printk ("%s%s, %d (DEBUG) %s(): ",			\
+			KERN_DEBUG, __FILE__, __LINE__, __func__);	\
+		printk (f, ##a);					\
+	} while (0)
+#   define DASSERT(x)							\
+	do {								\
+		if (!x)							\
+			DPRINTF("Assertion failed at line %d.\n", __LINE__);\
+	} while (0)
 #else
-#define DPRINTF(x...)
+#   define DPRINTF(...) do {} while(0)
+#   define DASSERT(...) do {} while(0)
 #endif
 
 /*
  *	Defines, simple typedefs etc.
  */
 
-#define W9966_DRIVERNAME	"W9966CF Webcam"
+#define W9966_DRIVERNAME	"w9966cf"
 #define W9966_MAXCAMS		4	// Maximum number of cameras
-#define W9966_RBUFFER		2048	// Read buffer (must be an even number)
-#define W9966_SRAMSIZE		131072	// 128kb
-#define W9966_SRAMID		0x02	// check w9966cf.pdf
-
-// Empirically determined window limits
-#define W9966_WND_MIN_X		16
-#define W9966_WND_MIN_Y		14
-#define W9966_WND_MAX_X		705
-#define W9966_WND_MAX_Y		253
-#define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
-#define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
+#define W9966_RBUFFER		8096	// Read buffer (must be an even number)
+
+#define W9966_WND_MIN_W		2
+#define W9966_WND_MIN_H		1
 
 // Keep track of our current state
-#define W9966_STATE_PDEV	0x01
-#define W9966_STATE_CLAIMED	0x02
-#define W9966_STATE_VDEV	0x04
+#define W9966_STATE_PDEV	0x01	// pdev registered
+#define W9966_STATE_CLAIMED	0x02	// pdev claimed
+#define W9966_STATE_VDEV	0x04	// vdev registered
+#define W9966_STATE_BUFFER	0x08	// buffer allocated
+#define W9966_STATE_DETECTED	0x10	// model identified
+
+#define W9966_SAA7111_ID	0x24	// I2C device id
 
-#define W9966_I2C_W_ID		0x48
-#define W9966_I2C_R_ID		0x49
+#define W9966_I2C_UDELAY	5
+#define W9966_I2C_TIMEOUT	100
 #define W9966_I2C_R_DATA	0x08
 #define W9966_I2C_R_CLOCK	0x04
 #define W9966_I2C_W_DATA	0x02
 #define W9966_I2C_W_CLOCK	0x01
 
+#define MAX(a, b) ((a > b) ? a : b)
+#define MIN(a, b) ((a > b) ? b : a)
+
 struct w9966_dev {
-	u8 dev_state;
-	u8 i2c_state;
-	int ppmode;
-	struct parport* pport;
-	struct pardevice* pdev;
 	struct video_device vdev;
+	struct parport*     pport;
+	struct pardevice*   pdev;
+	int ppmode;
+
+	u8* buffer;
+	u8  dev_state;
+	u8  i2c_state;
 	u16 width;
 	u16 height;
+
+	// Image properties
 	u8 brightness;
 	s8 contrast;
 	s8 color;
 	s8 hue;
-	u8* buffer;
+
+	// Model specific:
+	const char* name;
+	u32 sramsize;
+	u8  sramid;		// reg 0x0c, bank layout
+	u8  cmask;		// reg 0x01, for polarity
+	u16 min_x, max_x;	// Capture window limits
+	u16 min_y, max_y;
+	int (*image)(struct w9966_dev* cam);
 };
 
 /*
- *	Module specific properties
+ *	Module properties
  */
 
 MODULE_AUTHOR("Jakob Kemi <jakob.kemi@telia.com>");
-MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)");
+MODULE_DESCRIPTION("Winbond w9966cf webcam driver (Flycam Supra and others)");
 MODULE_LICENSE("GPL");
 
 
-static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"};
+static const char* pardev[] = {[0 ... W9966_MAXCAMS-1] = "auto"};
 MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s");
 MODULE_PARM_DESC(pardev,"\n\
 <auto|name|none[,...]> Where to find cameras.\n\
-  auto = probe all parports for camera\n\
+  auto = probe all parports for camera (default)\n\
   name = name of parport (eg parport0)\n\
-  none = don't search for this camera\n\
-You can specify all cameras this way, for example:
+  none = don't use this camera\n\
+You can specify all cameras this way, for example:\n\
   pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\
   for cam2 on all parports, skip cam3 and search for cam4 on parport0");
 
-static int parmode = 0;
+static int parmode = 1;
 MODULE_PARM(parmode, "i");
-MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)");
+MODULE_PARM_DESC(parmode, "\n<0|1|2|3> transfer mode (0=auto, 1=ecp(default), 2=epp, 3=forced hw-ecp)");
 
-static int video_nr = -1;
-MODULE_PARM(video_nr, "i");
+static int video_nr[] = {[0 ... W9966_MAXCAMS-1] = -1};
+MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9966_MAXCAMS) "i");
+MODULE_PARM_DESC(video_nr,"\n\
+<-1|n[,...]> Specify V4L minor mode number.\n\
+  -1 = use next available (default)\n\
+   n = use minor number n (integer >= 0)\n\
+You can specify all cameras this way, for example:\n\
+  video_nr=-1,2,-1 would assign minor number 2 for cam2 and use auto for cam1,\n\
+  cam3 and cam4");
 
 /*
  *	Private data
  */
 
-static struct w9966_dev w9966_cams[W9966_MAXCAMS];
+static struct w9966_dev* w9966_cams;
 
 /*
- *	Private function declares
+ *	Private function declarations
  */
 
-static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
-static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
-static inline void w9966_pdev_claim(struct w9966_dev *vdev);
+static inline void w9966_flag_set(struct w9966_dev* cam, int flag) {
+	cam->dev_state |= flag;}
+
+static inline void w9966_flag_clear(struct w9966_dev* cam, int flag) {
+	cam->dev_state &= ~flag;}
+
+static inline int  w9966_flag_test(struct w9966_dev* cam, int flag) {
+	return (cam->dev_state & flag);}
+
+static inline int  w9966_pdev_claim(struct w9966_dev *vdev);
 static inline void w9966_pdev_release(struct w9966_dev *vdev);
 
-static int w9966_rReg(struct w9966_dev* cam, int reg);
-static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
-static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
-static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
-static int w9966_findlen(int near, int size, int maxlen);
-static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
-static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
+static int w9966_rreg(struct w9966_dev* cam, int reg);
+static int w9966_wreg(struct w9966_dev* cam, int reg, int data);
 
-static int  w9966_init(struct w9966_dev* cam, struct parport* port);
+static int  w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr);
 static void w9966_term(struct w9966_dev* cam);
+static int  w9966_setup(struct w9966_dev* cam);
+static int  w9966_findlen(int near, int size, int maxlen);
+static int  w9966_calcscale(int size, int min, int max,
+			int* beg, int* end, u8* factor);
+static int  w9966_window(struct w9966_dev* cam, int x1, int y1,
+			int x2, int y2, int w, int h);
+
+static int w9966_saa7111_init(struct w9966_dev* cam);
+static int w9966_saa7111_image(struct w9966_dev* cam);
+static int w9966_lc99053_init(struct w9966_dev* cam);
+static int w9966_lc99053_image(struct w9966_dev* cam);
 
 static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
 static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
@@ -156,116 +206,104 @@
 static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
 static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
 static int w9966_i2c_rbyte(struct w9966_dev* cam);
+static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg);
+static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data);
 
 static int  w9966_v4l_open(struct video_device *vdev, int mode);
 static void w9966_v4l_close(struct video_device *vdev);
-static int  w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock);
+static int  w9966_v4l_ioctl(struct video_device *vdev,
+			unsigned int cmd, void *arg);
+static long w9966_v4l_read(struct video_device *vdev,
+			char *buf, unsigned long count, int noblock);
 
 /*
- *	Private function defines
+ *	Private function definitions
  */
 
-
-// Set camera phase flags, so we know what to uninit when terminating 
-static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
-{
-	cam->dev_state = (cam->dev_state & ~mask) ^ val;
-}
-
-// Get camera phase flags
-static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
-{
-	return ((cam->dev_state & mask) == val);
-}
-
 // Claim parport for ourself
-static inline void w9966_pdev_claim(struct w9966_dev* cam)
+// 1 on success, else 0
+static inline int w9966_pdev_claim(struct w9966_dev* cam)
 {
-	if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
-		return;
-	parport_claim_or_block(cam->pdev);
-	w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
+	if (w9966_flag_test(cam, W9966_STATE_CLAIMED))
+		return 1;
+	if (parport_claim_or_block(cam->pdev) < 0)
+		return 0;
+	w9966_flag_set(cam, W9966_STATE_CLAIMED);
+	return 1;
 }
 
 // Release parport for others to use
 static inline void w9966_pdev_release(struct w9966_dev* cam)
 {
-	if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
+	if (!w9966_flag_test(cam, W9966_STATE_CLAIMED))
 		return;
 	parport_release(cam->pdev);
-	w9966_setState(cam, W9966_STATE_CLAIMED, 0);
+	w9966_flag_clear(cam, W9966_STATE_CLAIMED);
 }
- 
-// Read register from W9966 interface-chip
+
+// Read register from w9966 interface-chip
 // Expects a claimed pdev
 // -1 on error, else register data (byte)
-static int w9966_rReg(struct w9966_dev* cam, int reg)
+static int w9966_rreg(struct w9966_dev* cam, int reg)
 {
 	// ECP, read, regtransfer, REG, REG, REG, REG, REG
-	const unsigned char addr = 0x80 | (reg & 0x1f);
-	unsigned char val;
-	
-	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
-		return -1;
-	if (parport_write(cam->pport, &addr, 1) != 1)
-		return -1;
-	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
-		return -1;
-	if (parport_read(cam->pport, &val, 1) != 1)
+	const u8 addr = 0x80 | (reg & 0x1f);
+	u8 val;
+
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 ||
+	    parport_write(cam->pport, &addr, 1) != 1 ||
+	    parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 ||
+	    parport_read(cam->pport, &val, 1) != 1)
 		return -1;
 
 	return val;
 }
 
-// Write register to W9966 interface-chip
+// Write register to w9966 interface-chip
 // Expects a claimed pdev
-// -1 on error
-static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
+// 1 on success, else 0
+static int w9966_wreg(struct w9966_dev* cam, int reg, int data)
 {
 	// ECP, write, regtransfer, REG, REG, REG, REG, REG
-	const unsigned char addr = 0xc0 | (reg & 0x1f);
-	const unsigned char val = data;
-	
-	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
-		return -1;
-	if (parport_write(cam->pport, &addr, 1) != 1)
-		return -1;
-	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
-		return -1;
-	if (parport_write(cam->pport, &val, 1) != 1)
-		return -1;
+	const u8 addr = 0xc0 | (reg & 0x1f);
+	const u8 val = data;
 
-	return 0;
+	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0 ||
+	    parport_write(cam->pport, &addr, 1) != 1 ||
+	    parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0 ||
+	    parport_write(cam->pport, &val, 1) != 1)
+		return 0;
+
+	return 1;
 }
 
 // Initialize camera device. Setup all internal flags, set a
 // default video mode, setup ccd-chip, register v4l device etc..
 // Also used for 'probing' of hardware.
-// -1 on error
-static int w9966_init(struct w9966_dev* cam, struct parport* port)
+// 1 on success, else 0
+static int w9966_init(struct w9966_dev* cam, struct parport* port, int vidnr)
 {
 	if (cam->dev_state != 0)
-		return -1;
-	
+		return 0;
+
 	cam->pport = port;
 	cam->brightness = 128;
 	cam->contrast = 64;
 	cam->color = 64;
 	cam->hue = 0;
 
-// Select requested transfer mode
+	// Select requested transfer mode
 	switch(parmode)
 	{
 	default:	// Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
 	case 0:
 		if (port->modes & PARPORT_MODE_ECP)
 			cam->ppmode = IEEE1284_MODE_ECP;
-/*		else if (port->modes & PARPORT_MODE_EPP)
-			cam->ppmode = IEEE1284_MODE_EPP;*/
+		else if (port->modes & PARPORT_MODE_EPP)
+			cam->ppmode = IEEE1284_MODE_EPP;
 		else
 			cam->ppmode = IEEE1284_MODE_ECPSWE;
-		break;	
+		break;
 	case 1:		// hw- or sw-ecp
 		if (port->modes & PARPORT_MODE_ECP)
 			cam->ppmode = IEEE1284_MODE_ECP;
@@ -278,27 +316,55 @@
 		else
 			cam->ppmode = IEEE1284_MODE_EPPSWE;
 		break;
+	case 3:		// hw-ecp
+		cam->ppmode = IEEE1284_MODE_ECP;
+		break;
 	}
-	
-// Tell the parport driver that we exists
-	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
+
+	// Tell the parport driver that we exists
+	cam->pdev = parport_register_device(
+	    port, W9966_DRIVERNAME, NULL, NULL, NULL, 0, NULL);
+
 	if (cam->pdev == NULL) {
-		DPRINTF("parport_register_device() failed\n");
-		return -1;
+		DPRINTF("parport_register_device() failed.\n");
+		return 0;
 	}
-	w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
+	w9966_flag_set(cam, W9966_STATE_PDEV);
 
-	w9966_pdev_claim(cam);
-	
-// Setup a default capture mode
-	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
+	// Claim parport
+	if (!w9966_pdev_claim(cam)) {
+		DPRINTF("w9966_pdev_claim() failed.\n");
+		return 0;
+	}
+
+	// Perform initial w9966 setup
+	if (!w9966_setup(cam)) {
 		DPRINTF("w9966_setup() failed.\n");
-		return -1;
+		return 0;
 	}
 
+	// Detect model
+	if (!w9966_saa7111_init(cam)) {
+		DPRINTF("w9966_saa7111_init() failed.\n");
+		return 0;
+	}
+	if (!w9966_lc99053_init(cam)) {
+		DPRINTF("w9966_lc99053_init() failed.\n");
+		return 0;
+	}
+	if (!w9966_flag_test(cam, W9966_STATE_DETECTED)) {
+		DPRINTF("Camera model not identified.\n");
+		return 0;
+	}
+
+	// Setup w9966 with a default capture mode (QCIF res.)
+	if (!w9966_window(cam, 0, 0, 1023, 1023, 176, 144)) {
+		DPRINTF("w9966_window() failed.\n");
+		return 0;
+	}
 	w9966_pdev_release(cam);
 
-// Fill in the video_device struct and register us to v4l
+	// Fill in the video_device struct and register us to v4l
 	memset(&cam->vdev, 0, sizeof(struct video_device));
 	strcpy(cam->vdev.name, W9966_DRIVERNAME);
 	cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
@@ -310,51 +376,73 @@
 	cam->vdev.priv = (void*)cam;
 	cam->vdev.owner = THIS_MODULE;
 
-	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)		 
-		return -1;
-	
-	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
-	
-	cam->buffer = NULL;
-	
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, vidnr) == -1) {
+		DPRINTF("video_register_device() failed (minor: %d).\n", vidnr);
+		return 0;
+	}
+	w9966_flag_set(cam, W9966_STATE_VDEV);
+
 	// All ok
-	printk(
-		"w9966cf: Found and initialized a webcam on %s.\n",
-		cam->pport->name
-	);
-	return 0;
+	printk("w9966: Found and initialized %s on %s.\n",
+		cam->name, cam->pport->name);
+	return 1;
 }
 
-
 // Terminate everything gracefully
 static void w9966_term(struct w9966_dev* cam)
 {
-// Delete allocated buffer if needed
-	if (cam->buffer != NULL) {
+	// Delete allocated buffer
+	if (w9966_flag_test(cam, W9966_STATE_BUFFER))
 		kfree(cam->buffer);
-		cam->buffer = NULL;
-	}
 
-// Unregister from v4l
-	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
+	// Unregister from v4l
+	if (w9966_flag_test(cam, W9966_STATE_VDEV))
 		video_unregister_device(&cam->vdev);
-		w9966_setState(cam, W9966_STATE_VDEV, 0);
-	}
 
-// Terminate from IEEE1284 mode and release pdev block
-	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
-		w9966_pdev_claim(cam);
-		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
-		w9966_pdev_release(cam);
-	}
+	// Terminate from IEEE1284 mode and unregister from parport
+	if (w9966_flag_test(cam, W9966_STATE_PDEV)) {
+		if (w9966_pdev_claim(cam))
+			parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
 
-// Unregister from parport
-	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
+		w9966_pdev_release(cam);
 		parport_unregister_device(cam->pdev);
-		w9966_setState(cam, W9966_STATE_PDEV, 0);
 	}
+
+	cam->dev_state = 0x00;
 }
 
+// Do initial setup for the w9966 chip, init i2c bus, etc.
+// this is generic for all models
+// expects a claimed pdev
+// 1 on success, else 0
+static int w9966_setup(struct w9966_dev* cam)
+{
+	const u8 i2c = cam->i2c_state = W9966_I2C_W_DATA | W9966_I2C_W_CLOCK;
+	const u8 regs[] = {
+		0x40,			// 0x13 - VEE control (raw 4:2:2)
+		0x00, 0x00, 0x00,	// 0x14 - 0x16
+		0x00,			// 0x17 - ???
+		i2c,			// 0x18 - Serial bus
+		0xff,			// 0x19 - I/O port direction control
+		0xff,			// 0x1a - I/O port data register
+		0x10			// 0x1b - ???
+	};
+	int i;
+
+	DASSERT(w9966_flag_test(cam, W9966_STATE_CLAIMED));
+
+	// Reset (ECP-fifo & serial-bus)
+	if (!w9966_wreg(cam, 0x00, 0x03) ||
+	    !w9966_wreg(cam, 0x00, 0x00))
+		return 0;
+
+	// Write regs to w9966cf chip
+	for (i = 0x13; i < 0x1c; i++)
+		if (!w9966_wreg(cam, i, regs[i-0x13]))
+			return 0;
+
+	return 1;
+}
 
 // Find a good length for capture window (used both for W and H)
 // A bit ugly but pretty functional. The capture length
@@ -365,7 +453,7 @@
 	int besterr = abs(near - bestlen);
 	int len;
 
-	for(len = size+1;len < maxlen;len++)
+	for(len = size+1; len < maxlen; len++)
 	{
 		int err;
 		if ( ((64*size) %len) != 0)
@@ -376,7 +464,7 @@
 		// Only continue as long as we keep getting better values
 		if (err > besterr)
 			break;
-		
+
 		besterr = err;
 		bestlen = len;
 	}
@@ -384,19 +472,19 @@
 	return bestlen;
 }
 
-// Modify capture window (if necessary) 
+// Modify capture window (if necessary)
 // and calculate downscaling
-// Return -1 on error
-static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
+// 1 on success, else 0
+static int w9966_calcscale(int size, int min, int max, int* beg, int* end, u8* factor)
 {
-	int maxlen = max - min;
-	int len = *end - *beg + 1;
-	int newlen = w9966_findlen(len, size, maxlen);
-	int err = newlen - len; 
+	const int maxlen = max - min;
+	const int len = *end - *beg + 1;
+	const int newlen = w9966_findlen(len, size, maxlen);
+	const int err = newlen - len;
 
 	// Check for bad format
 	if (newlen > maxlen || newlen < size)
-		return -1;
+		return 0;
 
 	// Set factor (6 bit fixed)
 	*factor = (64*size) / newlen;
@@ -419,62 +507,49 @@
 		*end -= *end - max;
 	}
 
-	return 0;
+	return 1;
 }
 
-// Setup the cameras capture window etc.
-// Expects a claimed pdev
-// return -1 on error
-static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
+// Setup the w9966 capture window and also set SRAM settings
+// expects a claimed pdev and detected camera model
+// 1 on success, else 0
+static int w9966_window(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
 {
-	unsigned int i;
 	unsigned int enh_s, enh_e;
 	u8 scale_x, scale_y;
-	u8 regs[0x1c];
-	u8 saa7111_regs[] = {
-		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
-		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
-		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
-	};
-	
-	
-	if (w*h*2 > W9966_SRAMSIZE)
-	{
-		DPRINTF("capture window exceeds SRAM size!.\n");
-		w = 200; h = 160;	// Pick default values
-	}
+	u8 regs[0x13];
+	int i;
 
+	// Modify width and height to match capture window and SRAM
+	w = MAX(W9966_WND_MIN_W, w);
+	h = MAX(W9966_WND_MIN_H, h);
+	w = MIN(cam->max_x - cam->min_x, w);
+	h = MIN(cam->max_y - cam->min_y, h);
 	w &= ~0x1;
-	if (w < 2) w = 2;
-	if (h < 1) h = 1;
-	if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
-	if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
+	if (w*h*2 > cam->sramsize)
+		h = cam->sramsize / (w*2);
 
 	cam->width = w;
 	cam->height = h;
 
-	enh_s = 0;	
+	enh_s = 0;
 	enh_e = w*h*2;
-	
-// Modify capture window if necessary and calculate downscaling
-	if (
-		w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
-		w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
-	) return -1;
-
-	DPRINTF(
-		"%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
-		w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
-	);
-	
-// Setup registers
+
+	// Calculate downscaling
+	if (!w9966_calcscale(w, cam->min_x, cam->max_x, &x1, &x2, &scale_x) ||
+	    !w9966_calcscale(h, cam->min_y, cam->max_y, &y1, &y2, &scale_y))
+		return 0;
+
+	DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
+		w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80);
+
+	// Setup registers
 	regs[0x00] = 0x00;			// Set normal operation
-	regs[0x01] = 0x18;			// Capture mode
+	regs[0x01] = cam->cmask;		// Capture mode
 	regs[0x02] = scale_y;			// V-scaling
 	regs[0x03] = scale_x;			// H-scaling
-	
-	// Capture window	
+
+	// Capture window
 	regs[0x04] = (x1 & 0x0ff);		// X-start (8 low bits)
 	regs[0x05] = (x1 & 0x300)>>8;		// X-start (2 high bits)
 	regs[0x06] = (y1 & 0x0ff);		// Y-start (8 low bits)
@@ -483,8 +558,8 @@
 	regs[0x09] = (x2 & 0x300)>>8;		// X-end (2 high bits)
 	regs[0x0a] = (y2 & 0x0ff);		// Y-end (8 low bits)
 
-	regs[0x0c] = W9966_SRAMID;		// SRAM-banks (1x 128kb)
-	
+	regs[0x0c] = cam->sramid;		// SRAM layout
+
 	// Enhancement layer
 	regs[0x0d] = (enh_s& 0x000ff);		// Enh. start (0-7)
 	regs[0x0e] = (enh_s& 0x0ff00)>>8;	// Enh. start (8-15)
@@ -493,35 +568,110 @@
 	regs[0x11] = (enh_e& 0x0ff00)>>8;	// Enh. end (8-15)
 	regs[0x12] = (enh_e& 0x70000)>>16;	// Enh. end (16-17/18??)
 
-	// Misc
-	regs[0x13] = 0x40;			// VEE control (raw 4:2:2)
-	regs[0x17] = 0x00;			// ???
-	regs[0x18] = cam->i2c_state = 0x00;	// Serial bus
-	regs[0x19] = 0xff;			// I/O port direction control
-	regs[0x1a] = 0xff;			// I/O port data register
-	regs[0x1b] = 0x10;			// ???
-	
-	// SAA7111 chip settings
-	saa7111_regs[0x0a] = cam->brightness;
-	saa7111_regs[0x0b] = cam->contrast;
-	saa7111_regs[0x0c] = cam->color;
-	saa7111_regs[0x0d] = cam->hue;
+	// Write regs to w9966cf chip
+	for (i = 0x01; i < 0x13; i++)
+		if (!w9966_wreg(cam, i, regs[i]))
+			return 0;
+
+	return 1;
+}
+
+// Detect and initialize saa7111 ccd-controller chip.
+// expects a claimed parport
+// expected to always return 1 unless error is _fatal_
+// 1 on success, else 0
+static int w9966_saa7111_init(struct w9966_dev* cam)
+{
+	// saa7111 regs 0x00 trough 0x12
+	const u8 regs[] = {
+		0x00, // not written
+		0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10,
+		cam->brightness,	// 0x0a
+		cam->contrast,		// 0x0b
+		cam->color,		// 0x0c
+		cam->hue,		// 0x0d
+		0x01, 0x00, 0x48, 0x0c, 0x00,
+	};
+	int i;
 
-// Reset (ECP-fifo & serial-bus)
-	if (w9966_wReg(cam, 0x00, 0x03) == -1)
-		return -1;
+	if (w9966_flag_test(cam, W9966_STATE_DETECTED))
+		return 1;
 
-// Write regs to w9966cf chip
-	for (i = 0; i < 0x1c; i++)
-		if (w9966_wReg(cam, i, regs[i]) == -1)
-			return -1;
+	// Write regs to saa7111 chip
+	for (i = 1; i < 0x13; i++)
+		if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, i, regs[i]))
+			return 1;
+
+	// Read back regs
+	for (i = 1; i < 0x13; i++)
+		if (w9966_i2c_rreg(cam, W9966_SAA7111_ID, i) != regs[i])
+			return 1;
+
+	// Fill in model specific data
+	cam->name = "Lifeview Flycam Supra";
+	cam->sramsize = 128 << 10;	// 128 kib
+	cam->sramid = 0x02;		// see w9966.pdf
+
+	cam->cmask = 0x18;		// normal polarity
+	cam->min_x = 16;		// empirically determined
+	cam->max_x = 705;
+	cam->min_y = 14;
+	cam->max_y = 253;
+	cam->image = &w9966_saa7111_image;
+
+	DPRINTF("Found and initialized a saa7111 chip.\n");
+	w9966_flag_set(cam, W9966_STATE_DETECTED);
+
+	return 1;
+}
+
+// Setup image properties (brightness, hue, etc.) for the saa7111 chip
+// expects a claimed parport
+// 1 on success, else 0
+static int w9966_saa7111_image(struct w9966_dev* cam)
+{
+	if (!w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0a, cam->brightness) ||
+	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0b, cam->contrast) ||
+	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0c, cam->color) ||
+	    !w9966_i2c_wreg(cam, W9966_SAA7111_ID, 0x0d, cam->hue))
+		return 0;
 
-// Write regs to saa7111 chip
-	for (i = 0; i < 0x20; i++)
-		if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
-			return -1;
+	return 1;
+}
 
-	return 0;
+// Detect and initialize lc99053 ccd-controller chip.
+// expects a claimed parport
+// this is currently a hack, no detection is done, we just assume an Eyestar2
+// 1 on success, else 0
+static int w9966_lc99053_init(struct w9966_dev* cam)
+{
+	if (w9966_flag_test(cam, W9966_STATE_DETECTED))
+		return 1;
+
+	// Fill in model specific data
+	cam->name = "Microtek Eyestar2";
+	cam->sramsize = 128 << 10;	// 128 kib
+	cam->sramid = 0x02;		// w9966cf.pdf
+
+	cam->cmask = 0x10;		// reverse polarity
+	cam->min_x = 16;		// empirically determined
+	cam->max_x = 705;
+	cam->min_y = 14;
+	cam->max_y = 253;
+	cam->image = &w9966_lc99053_image;
+
+	DPRINTF("Found and initialized a lc99053 chip.\n");
+	w9966_flag_set(cam, W9966_STATE_DETECTED);
+
+	return 1;
+}
+
+// Setup image properties (brightness, hue, etc.) for the lc99053 chip
+// expects a claimed parport
+// 1 on success, else 0
+static int w9966_lc99053_image(struct w9966_dev* cam)
+{
+	return 1;
 }
 
 /*
@@ -536,91 +686,90 @@
 		cam->i2c_state |= W9966_I2C_W_DATA;
 	else
 		cam->i2c_state &= ~W9966_I2C_W_DATA;
-	
-	w9966_wReg(cam, 0x18, cam->i2c_state);
-	udelay(5);
+
+	w9966_wreg(cam, 0x18, cam->i2c_state);
+	udelay(W9966_I2C_UDELAY);
 }
 
 // Sets the clock line on the i2c bus.
-// Expects a claimed pdev. -1 on error
+// Expects a claimed pdev.
+// 1 on success, else 0
 static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
 {
-	int timeout;
 	if (state)
 		cam->i2c_state |= W9966_I2C_W_CLOCK;
 	else
 		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
 
-	w9966_wReg(cam, 0x18, cam->i2c_state);
-	udelay(5);
-	
-	// we go to high, we also expect the peripheral to ack.
+	w9966_wreg(cam, 0x18, cam->i2c_state);
+	udelay(W9966_I2C_UDELAY);
+
+	// when we go to high, we also expect the peripheral to ack.
 	if (state) {
-		timeout = jiffies + 100;
+		const int timeout = jiffies + W9966_I2C_TIMEOUT;
 		while (!w9966_i2c_getscl(cam)) {
 			if (time_after(jiffies, timeout))
-				return -1;
+				return 0;
 		}
 	}
-	return 0;
+	return 1;
 }
 
 // Get peripheral data line
 // Expects a claimed pdev.
 static inline int w9966_i2c_getsda(struct w9966_dev* cam)
 {
-	const unsigned char state = w9966_rReg(cam, 0x18);
-	return ((state & W9966_I2C_R_DATA) > 0);
+	const u8 pins = w9966_rreg(cam, 0x18);
+	return ((pins & W9966_I2C_R_DATA) > 0);
 }
 
 // Get peripheral clock line
 // Expects a claimed pdev.
 static inline int w9966_i2c_getscl(struct w9966_dev* cam)
 {
-	const unsigned char state = w9966_rReg(cam, 0x18);
-	return ((state & W9966_I2C_R_CLOCK) > 0);
+	const u8 pins = w9966_rreg(cam, 0x18);
+	return ((pins & W9966_I2C_R_CLOCK) > 0);
 }
 
 // Write a byte with ack to the i2c bus.
-// Expects a claimed pdev. -1 on error
+// Expects a claimed pdev.
+// 1 on success, else 0
 static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
 {
 	int i;
-	for (i = 7; i >= 0; i--)
-	{
+	for (i = 7; i >= 0; i--) {
 		w9966_i2c_setsda(cam, (data >> i) & 0x01);
 
-		if (w9966_i2c_setscl(cam, 1) == -1)
-			return -1;			
-		w9966_i2c_setscl(cam, 0);
+		if (!w9966_i2c_setscl(cam, 1) ||
+		    !w9966_i2c_setscl(cam, 0))
+			return 0;
 	}
-
 	w9966_i2c_setsda(cam, 1);
-	
-	if (w9966_i2c_setscl(cam, 1) == -1)
-		return -1;
-	w9966_i2c_setscl(cam, 0);
-	
-	return 0;
+
+	if (!w9966_i2c_setscl(cam, 1) ||
+	    !w9966_i2c_setscl(cam, 0))
+		return 0;
+
+	return 1;
 }
 
 // Read a data byte with ack from the i2c-bus
 // Expects a claimed pdev. -1 on error
 static int w9966_i2c_rbyte(struct w9966_dev* cam)
 {
-	unsigned char data = 0x00;
-	int i;	
-	
+	u8 data = 0x00;
+	int i;
+
 	w9966_i2c_setsda(cam, 1);
 
 	for (i = 0; i < 8; i++)
 	{
-		if (w9966_i2c_setscl(cam, 1) == -1)
+		if (!w9966_i2c_setscl(cam, 1))
 			return -1;
 		data = data << 1;
 		if (w9966_i2c_getsda(cam))
 			data |= 0x01;
-		
+
 		w9966_i2c_setscl(cam, 0);
 	}
 	return data;
@@ -628,75 +777,81 @@
 
 // Read a register from the i2c device.
 // Expects claimed pdev. -1 on error
-static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
+static int w9966_i2c_rreg(struct w9966_dev* cam, int device, int reg)
 {
 	int data;
 
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
-		w9966_i2c_wbyte(cam, reg) == -1
-	)
+	if (!w9966_i2c_wbyte(cam, device << 1) ||
+	    !w9966_i2c_wbyte(cam, reg))
 		return -1;
 
 	w9966_i2c_setsda(cam, 1);
-	if (w9966_i2c_setscl(cam, 1) == -1)
+	if (!w9966_i2c_setscl(cam, 1))
 		return -1;
+
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
-		(data = w9966_i2c_rbyte(cam)) == -1
-	)
+	if (!w9966_i2c_wbyte(cam, (device << 1) | 1) ||
+	    (data = w9966_i2c_rbyte(cam)) == -1)
 		return -1;
 
 	w9966_i2c_setsda(cam, 0);
-	
-	if (w9966_i2c_setscl(cam, 1) == -1)
+
+	if (!w9966_i2c_setscl(cam, 1))
 		return -1;
+
 	w9966_i2c_setsda(cam, 1);
-	
+
 	return data;
 }
 
-
 // Write a register to the i2c device.
-// Expects claimed pdev. -1 on error
-static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
+// Expects claimed pdev.
+// 1 on success, else 0
+static int w9966_i2c_wreg(struct w9966_dev* cam, int device, int reg, int data)
 {
 	w9966_i2c_setsda(cam, 0);
 	w9966_i2c_setscl(cam, 0);
 
-	if (
-		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
-		w9966_i2c_wbyte(cam, reg) == -1 ||
-		w9966_i2c_wbyte(cam, data) == -1
-	)
-		return -1;
+	if (!w9966_i2c_wbyte(cam, device << 1) ||
+	    !w9966_i2c_wbyte(cam, reg) ||
+	    !w9966_i2c_wbyte(cam, data))
+		return 0;
 
 	w9966_i2c_setsda(cam, 0);
-	if (w9966_i2c_setscl(cam, 1) == -1)
-		return -1;
-		
+	if (!w9966_i2c_setscl(cam, 1))
+		return 0;
+
 	w9966_i2c_setsda(cam, 1);
 
-	return 0;
+	return 1;
 }
 
 /*
- *	Video4linux interfacing
+ *	Video4linux interface
  */
 
 static int w9966_v4l_open(struct video_device *vdev, int flags)
 {
 	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
-	cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);
-	
-	if (cam->buffer == NULL)
+
+	// Claim parport
+	if (!w9966_pdev_claim(cam)) {
+		DPRINTF("Unable to claim parport");
 		return -EFAULT;
+	}
+
+	// Allocate read buffer
+	cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL);
+	if (cam->buffer == NULL) {
+		w9966_pdev_release(cam);
+		return -ENOMEM;
+	}
+	w9966_flag_set(cam, W9966_STATE_BUFFER);
 
 	return 0;
 }
@@ -704,17 +859,22 @@
 static void w9966_v4l_close(struct video_device *vdev)
 {
 	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
-	
-	if (cam->buffer != NULL) {
+
+	// Free read buffer
+	if (w9966_flag_test(cam, W9966_STATE_BUFFER)) {
 		kfree(cam->buffer);
-		cam->buffer = NULL;
+		w9966_flag_clear(cam, W9966_STATE_BUFFER);
 	}
+
+	// release parport
+	w9966_pdev_release(cam);
 }
 
+// expects a claimed parport
 static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
-	
+
 	switch(cmd)
 	{
 	case VIDIOCGCAP:
@@ -723,9 +883,10 @@
 			W9966_DRIVERNAME,	// name
 			VID_TYPE_CAPTURE | VID_TYPE_SCALES,	// type
 			1, 0,			// vid, aud channels
-			W9966_WND_MAX_W,	// max w
-			W9966_WND_MAX_H,	// max h
-			2, 1			// min w, min h
+			cam->max_x - cam->min_x,
+			cam->max_y - cam->min_y,
+			W9966_WND_MIN_W,
+			W9966_WND_MIN_H
 		};
 
 		if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0)
@@ -747,10 +908,10 @@
 		vch.tuners = 0;
 		vch.type = VIDEO_TYPE_CAMERA;
 		vch.norm = 0;		// ???
-		
+
 		if(copy_to_user(arg, &vch, sizeof(vch)) != 0)
 			return -EFAULT;
-		
+
 		return 0;
 	}
 	case VIDIOCSCHAN:
@@ -758,10 +919,10 @@
 		struct video_channel vch;
 		if(copy_from_user(&vch, arg, sizeof(vch) ) != 0)
 			return -EFAULT;
-		
+
 		if(vch.channel != 0)
 			return -EINVAL;
-		
+
 		return 0;
 	}
 	case VIDIOCGTUNER:
@@ -769,20 +930,20 @@
 		struct video_tuner vtune;
 		if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
 			return -EFAULT;
-		
+
 		if(vtune.tuner != 0);
 			return -EINVAL;
-		
+
 		strcpy(vtune.name, "no tuner");
 		vtune.rangelow = 0;
 		vtune.rangehigh = 0;
 		vtune.flags = VIDEO_TUNER_NORM;
 		vtune.mode = VIDEO_MODE_AUTO;
 		vtune.signal = 0xffff;
-		
+
 		if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)
 			return -EFAULT;
-		
+
 		return 0;
 	}
 	case VIDIOCSTUNER:
@@ -790,13 +951,13 @@
 		struct video_tuner vtune;
 		if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
 			return -EFAULT;
-		
+
 		if (vtune.tuner != 0)
 			return -EINVAL;
-		
+
 		if (vtune.mode != VIDEO_MODE_AUTO)
 			return -EINVAL;
-		
+
 		return 0;
 	}
 	case VIDIOCGPICT:
@@ -820,73 +981,58 @@
 		struct video_picture vpic;
 		if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0)
 			return -EFAULT;
-		
+
 		if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)
 			return -EINVAL;
-			
+
 		cam->brightness = vpic.brightness >> 8;
 		cam->hue = (vpic.hue >> 8) - 128;
 		cam->color = vpic.colour >> 9;
 		cam->contrast = vpic.contrast >> 9;
 
-		w9966_pdev_claim(cam);
-		
-		if (
-			w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
-			w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
-			w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
-			w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
-		) {
-			w9966_pdev_release(cam);
+		if (!cam->image(cam))
 			return -EFAULT;
-		}
-		
-		w9966_pdev_release(cam);
+
 		return 0;
 	}
 	case VIDIOCSWIN:
 	{
-		int ret;
 		struct video_window vwin;
-		
+
 		if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0)
-			return -EFAULT;		
-		if (vwin.flags != 0)
-			return -EINVAL;
-		if (vwin.clipcount != 0)
+			return -EFAULT;
+		if (
+		  vwin.flags != 0 ||
+		  vwin.clipcount != 0)
 			return -EINVAL;
-		if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W)
-			return -EINVAL;		
-		if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H)
+
+		if (vwin.width  > cam->max_x - cam->min_x ||
+		    vwin.height > cam->max_y - cam->min_y ||
+		    vwin.width  < W9966_WND_MIN_W ||
+		    vwin.height < W9966_WND_MIN_H)
 			return -EINVAL;
 
 		// Update camera regs
-		w9966_pdev_claim(cam);
-		ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height);
-		w9966_pdev_release(cam);
-		
-		if (ret != 0) {
-			DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
+		if (!w9966_window(cam, 0, 0, 1023, 1023, vwin.width, vwin.height))
 			return -EFAULT;
-		}
-		
+
 		return 0;
 	}
 	case VIDIOCGWIN:
 	{
 		struct video_window vwin;
 		memset(&vwin, 0, sizeof(vwin));
-		
+
 		vwin.width = cam->width;
 		vwin.height = cam->height;
-		
+
 		if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)
 			return -EFAULT;
-		
+
 		return 0;
 	}
 	// Unimplemented
-	case VIDIOCCAPTURE:	
+	case VIDIOCCAPTURE:
 	case VIDIOCGFBUF:
 	case VIDIOCSFBUF:
 	case VIDIOCKEY:
@@ -902,69 +1048,62 @@
 }
 
 // Capture data
+// expects a claimed parport and allocated read buffer
 static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count,  int noblock)
 {
 	struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;
-	unsigned char addr = 0xa0;	// ECP, read, CCD-transfer, 00000
-	unsigned char* dest = (unsigned char*)buf;
+	const u8 addr = 0xa0;	// ECP, read, CCD-transfer, 00000
+	u8* dest = (u8*)buf;
 	unsigned long dleft = count;
-	
+
 	// Why would anyone want more than this??
 	if (count > cam->width * cam->height * 2)
 		return -EINVAL;
-	
-	w9966_pdev_claim(cam);
-	w9966_wReg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer
-	w9966_wReg(cam, 0x00, 0x00);	// Return to normal operation
-	w9966_wReg(cam, 0x01, 0x98);	// Enable capture
-
-	// write special capture-addr and negotiate into data transfer	
-	if (
-		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0	)||
-		(parport_write(cam->pport, &addr, 1) != 1						)||
-		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0	)
-	) {
-		w9966_pdev_release(cam);
+
+	w9966_wreg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer
+	w9966_wreg(cam, 0x00, 0x00);	// Return to normal operation
+	w9966_wreg(cam, 0x01, cam->cmask | 0x80);	// Enable capture
+
+	// write special capture-addr and negotiate into data transfer
+	if (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 ||
+	    parport_write(cam->pport, &addr, 1) != 1 ||
+	    parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0) {
+		DPRINTF("Unable to write capture-addr.\n");
 		return -EFAULT;
 	}
-	
+
 	while(dleft > 0)
 	{
-		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
-	
-		if (parport_read(cam->pport, cam->buffer, tsize) < tsize) {
-			w9966_pdev_release(cam);
+		const size_t tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
+
+		if (parport_read(cam->pport, cam->buffer, tsize) < tsize)
 			return -EFAULT;
-		}
-		if (copy_to_user(dest, cam->buffer, tsize) != 0) {
-			w9966_pdev_release(cam);
+
+		if (copy_to_user(dest, cam->buffer, tsize) != 0)
 			return -EFAULT;
-		}
+
 		dest += tsize;
 		dleft -= tsize;
 	}
-	
-	w9966_wReg(cam, 0x01, 0x18);	// Disable capture
-	w9966_pdev_release(cam);
+
+	w9966_wreg(cam, 0x01, cam->cmask);	// Disable capture
 
 	return count;
 }
 
-
 // Called once for every parport on init
 static void w9966_attach(struct parport *port)
 {
 	int i;
-	
-	for (i = 0; i < W9966_MAXCAMS; i++)
-	{
-		if (strcmp(pardev[i], "none") == 0)	// Skip if 'none'
-			continue;
-		if (w9966_cams[i].dev_state != 0)	// Cam is already assigned
+
+	for (i = 0; i < W9966_MAXCAMS; i++) {
+		if (strcmp(pardev[i], "none") == 0 ||	// Skip if 'none' or if
+		    w9966_cams[i].dev_state != 0)	// cam already assigned
 			continue;
+
 		if (strcmp(pardev[i], "auto") == 0 ||
 		    strcmp(pardev[i], port->name) == 0) {
-			if (w9966_init(&w9966_cams[i], port) != 0)
+			if (!w9966_init(&w9966_cams[i], port, video_nr[i]))
 				w9966_term(&w9966_cams[i]);
 			break;	// return
 		}
@@ -991,16 +1130,33 @@
 // Module entry point
 static int __init w9966_mod_init(void)
 {
-	int i;
+	int i, err;
+
+	w9966_cams = kmalloc(
+		sizeof(struct w9966_dev) * W9966_MAXCAMS, GFP_KERNEL);
+
+	if (!w9966_cams)
+		return -ENOMEM;
+
 	for (i = 0; i < W9966_MAXCAMS; i++)
 		w9966_cams[i].dev_state = 0;
 
-	return parport_register_driver(&w9966_ppd);
+	// Register parport driver
+	if ((err = parport_register_driver(&w9966_ppd)) != 0) {
+		kfree(w9966_cams);
+		w9966_cams = 0;
+		return err;
+	}
+
+	return 0;
 }
 
 // Module cleanup
 static void __exit w9966_mod_term(void)
 {
+	if (w9966_cams)
+		kfree(w9966_cams);
+
 	parport_unregister_driver(&w9966_ppd);
 }
 
diff -urN linux-2.4.19-pre2/drivers/mtd/chips/sharp.c linux-2.4.19-pre3/drivers/mtd/chips/sharp.c
--- linux-2.4.19-pre2/drivers/mtd/chips/sharp.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre3/drivers/mtd/chips/sharp.c	Mon Mar 11 14:13:28 2002
@@ -440,7 +440,7 @@
 
 	timeo = jiffies + HZ;
 
-	while(jiffies<timeo){
+	while(time_before(jiffies, timeo)){
 		map->write32(map,CMD_READ_STATUS,adr);
 		status = map->read32(map,adr);
 		if((status & SR_READY)==SR_READY){
diff -urN linux-2.4.19-pre2/drivers/net/7990.c linux-2.4.19-pre3/drivers/net/7990.c
--- linux-2.4.19-pre2/drivers/net/7990.c	Tue Feb 13 13:15:05 2001
+++ linux-2.4.19-pre3/drivers/net/7990.c	Mon Mar 11 14:13:28 2002
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -569,7 +570,7 @@
         struct dev_mc_list *dmi=dev->mc_list;
         char *addrs;
         int i, j, bit, byte;
-        u32 crc, poly = CRC_POLYNOMIAL_LE;
+        u32 crc;
         
         /* set all multicast bits */
         if (dev->flags & IFF_ALLMULTI){ 
@@ -590,21 +591,7 @@
                 if (!(*addrs & 1))
                         continue;
                 
-                crc = 0xffffffff;
-                for (byte = 0; byte < 6; byte++)
-                        for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
-                        {
-                                int test;
-
-                                test = ((bit ^ crc) & 0x01);
-                                crc >>= 1;
-
-                                if (test)
-                                {
-                                        crc = crc ^ poly;
-                                }
-                        }
-                
+		crc = ether_crc_le(6, addrs);
                 crc = crc >> 26;
                 mcast_table [crc >> 4] |= 1 << (crc & 0xf);
         }
diff -urN linux-2.4.19-pre2/drivers/net/7990.h linux-2.4.19-pre3/drivers/net/7990.h
--- linux-2.4.19-pre2/drivers/net/7990.h	Thu Jan  4 13:00:55 2001
+++ linux-2.4.19-pre3/drivers/net/7990.h	Mon Mar 11 14:13:28 2002
@@ -132,9 +132,6 @@
 	char tx_full;
 };
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
  *              Am7990 Control and Status Registers
  */
diff -urN linux-2.4.19-pre2/drivers/net/8139cp.c linux-2.4.19-pre3/drivers/net/8139cp.c
--- linux-2.4.19-pre2/drivers/net/8139cp.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/8139cp.c	Mon Mar 11 14:13:28 2002
@@ -55,6 +55,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <linux/mii.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -707,22 +708,6 @@
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	return crc;
-}
-
 static void __cp_set_rx_mode (struct net_device *dev)
 {
 	struct cp_private *cp = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/8139too.c linux-2.4.19-pre3/drivers/net/8139too.c
--- linux-2.4.19-pre2/drivers/net/8139too.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/8139too.c	Mon Mar 11 14:13:28 2002
@@ -109,6 +109,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/completion.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -597,7 +598,6 @@
 static int rtl8139_close (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
 static void rtl8139_set_rx_mode (struct net_device *dev);
 static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
@@ -2397,23 +2397,6 @@
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	return crc;
-}
-
-
 static void __set_rx_mode (struct net_device *dev)
 {
 	struct rtl8139_private *tp = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/8390.c linux-2.4.19-pre3/drivers/net/8390.c
--- linux-2.4.19-pre2/drivers/net/8390.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre3/drivers/net/8390.c	Mon Mar 11 14:13:28 2002
@@ -68,6 +68,7 @@
 #include <linux/in.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -885,27 +886,6 @@
 }
 
 /*
- * Update the given Autodin II CRC value with another data byte.
- */
-
-static inline u32 update_crc(u8 byte, u32 current_crc)
-{
-	int bit;
-	u8 ah = 0;
-	for (bit=0; bit<8; bit++) 
-	{
-		u8 carry = (current_crc>>31);
-		current_crc <<= 1;
-		ah = ((ah<<1) | carry) ^ byte;
-		if (ah&1)
-			current_crc ^= 0x04C11DB7;	/* CRC polynomial */
-		ah >>= 1;
-		byte >>= 1;
-	}
-	return current_crc;
-}
-
-/*
  * Form the 64 bit 8390 multicast table from the linked list of addresses
  * associated with this dev structure.
  */
@@ -916,16 +896,13 @@
 
 	for (dmi=dev->mc_list; dmi; dmi=dmi->next) 
 	{
-		int i;
 		u32 crc;
 		if (dmi->dmi_addrlen != ETH_ALEN) 
 		{
 			printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
 			continue;
 		}
-		crc = 0xffffffff;	/* initial CRC value */
-		for (i=0; i<ETH_ALEN; i++)
-			crc = update_crc(dmi->dmi_addr[i], crc);
+		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
 		/* 
 		 * The 8390 uses the 6 most significant bits of the
 		 * CRC to index the multicast table.
diff -urN linux-2.4.19-pre2/drivers/net/Config.in linux-2.4.19-pre3/drivers/net/Config.in
--- linux-2.4.19-pre2/drivers/net/Config.in	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/Config.in	Mon Mar 11 14:13:28 2002
@@ -68,9 +68,6 @@
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
-   if [ "$CONFIG_SGI_IP32" = "y" ]; then
-      tristate '  SGI O2 MACE Fast Ethernet support' CONFIG_SGI_O2MACE_ETH
-   fi
    if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
diff -urN linux-2.4.19-pre2/drivers/net/a2065.c linux-2.4.19-pre3/drivers/net/a2065.c
--- linux-2.4.19-pre2/drivers/net/a2065.c	Tue Oct 16 21:56:29 2001
+++ linux-2.4.19-pre3/drivers/net/a2065.c	Mon Mar 11 14:13:28 2002
@@ -6,6 +6,7 @@
  * Fixes and tips by:
  *	- Janos Farkas (CHEXUM@sparta.banki.hu)
  *	- Jes Degn Soerensen (jds@kom.auc.dk)
+ *	- Matt Domsch (Matt_Domsch@dell.com)
  *
  * ----------------------------------------------------------------------------
  *
@@ -47,6 +48,7 @@
 #include <linux/string.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -639,7 +641,7 @@
 	struct dev_mc_list *dmi=dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 	
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI){ 
@@ -660,21 +662,7 @@
 		if (!(*addrs & 1))
 			continue;
 		
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++)
-			for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
-			{
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test)
-				{
-					crc = crc ^ poly;
-				}
-			}
-		
+		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
 		mcast_table [crc >> 4] |= 1 << (crc & 0xf);
 	}
diff -urN linux-2.4.19-pre2/drivers/net/a2065.h linux-2.4.19-pre3/drivers/net/a2065.h
--- linux-2.4.19-pre2/drivers/net/a2065.h	Wed Jan 26 12:45:20 2000
+++ linux-2.4.19-pre3/drivers/net/a2065.h	Mon Mar 11 14:13:28 2002
@@ -43,9 +43,6 @@
 };
 
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
  *		Am7990 Control and Status Registers
  */
diff -urN linux-2.4.19-pre2/drivers/net/am79c961a.c linux-2.4.19-pre3/drivers/net/am79c961a.c
--- linux-2.4.19-pre2/drivers/net/am79c961a.c	Wed Jun 27 14:12:04 2001
+++ linux-2.4.19-pre3/drivers/net/am79c961a.c	Mon Mar 11 14:13:28 2002
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -308,33 +309,13 @@
 	return &priv->stats;
 }
 
-static inline u32 update_crc(u32 crc, u8 byte)
-{
-	int i;
-
-	for (i = 8; i != 0; i--) {
-		byte ^= crc & 1;
-		crc >>= 1;
-
-		if (byte & 1)
-			crc ^= 0xedb88320;
-
-		byte >>= 1;
-	}
-
-	return crc;
-}
-
 static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
 {
 	if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
-		int i, idx, bit;
+		int idx, bit;
 		u32 crc;
 
-		crc = 0xffffffff;
-
-		for (i = 0; i < ETH_ALEN; i++)
-			crc = update_crc(crc, dmi->dmi_addr[i]);
+		crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
 
 		idx = crc >> 30;
 		bit = (crc >> 26) & 15;
diff -urN linux-2.4.19-pre2/drivers/net/at1700.c linux-2.4.19-pre3/drivers/net/at1700.c
--- linux-2.4.19-pre2/drivers/net/at1700.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/at1700.c	Mon Mar 11 14:13:28 2002
@@ -49,6 +49,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -804,27 +805,6 @@
   Set the multicast/promiscuous mode for this adaptor.
 */
 
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 static void
 set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.4.19-pre2/drivers/net/atp.c linux-2.4.19-pre3/drivers/net/atp.c
--- linux-2.4.19-pre2/drivers/net/atp.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/atp.c	Mon Mar 11 14:13:28 2002
@@ -140,6 +140,7 @@
 #include <asm/dma.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -857,26 +858,6 @@
  *	Set or clear the multicast filter for this adapter.
  */
 
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-    unsigned int crc = 0xffffffff;	/* Initial value. */
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-    }
-    return crc;
-}
-
 static void set_rx_mode_8002(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/au1000_eth.c linux-2.4.19-pre3/drivers/net/au1000_eth.c
--- linux-2.4.19-pre2/drivers/net/au1000_eth.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/au1000_eth.c	Mon Mar 11 14:13:28 2002
@@ -47,6 +47,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
@@ -1242,23 +1243,6 @@
 	au1000_init(dev);
 }
 
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? 
-				 ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
 static void set_rx_mode(struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/bmac.c linux-2.4.19-pre3/drivers/net/bmac.c
--- linux-2.4.19-pre2/drivers/net/bmac.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/bmac.c	Mon Mar 11 14:13:28 2002
@@ -1048,16 +1048,13 @@
 
 /* The version of set_multicast below was lifted from sunhme.c */
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void bmac_set_multicast(struct net_device *dev)
 {
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
 	unsigned short rx_cfg;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
 		bmwrite(dev, BHASH0, 0xffff);
@@ -1084,17 +1081,7 @@
 			if(!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for(byte = 0; byte < 6; byte++) {
-				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if(test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.4.19-pre2/drivers/net/de4x5.c linux-2.4.19-pre3/drivers/net/de4x5.c
--- linux-2.4.19-pre2/drivers/net/de4x5.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/de4x5.c	Mon Mar 11 14:13:28 2002
@@ -436,6 +436,7 @@
                            'pb' is now only initialized if a de4x5 chip is
                            present. 
                            <france@handhelds.org>  
+      0.547  08-Nov-01    Use library crc32 functions by <Matt_Domsch@dell.com>
     =========================================================================
 */
 
@@ -457,6 +458,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/spinlock.h>
+#include <linux/crc32.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -622,9 +624,6 @@
 #define QUEUE_PKT_TIMEOUT (3*HZ)        /* 3 second timeout */
 
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
 ** EISA bus defines
 */
@@ -2050,7 +2049,7 @@
     u_long iobase = dev->base_addr;
     int i, j, bit, byte;
     u16 hashcode;
-    u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
+    u32 omr, crc;
     char *pa;
     unsigned char *addrs;
 
@@ -2065,13 +2064,7 @@
 	    addrs=dmi->dmi_addr;
 	    dmi=dmi->next;
 	    if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
-		crc = 0xffffffff;            /* init CRC for each address */
-		for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-		                             /* process each address bit */ 
-		    for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
-			crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
-		    }
-		}
+		crc = ether_crc_le(ETH_ALEN, addrs);
 		hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
 		
 		byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
diff -urN linux-2.4.19-pre2/drivers/net/declance.c linux-2.4.19-pre3/drivers/net/declance.c
--- linux-2.4.19-pre2/drivers/net/declance.c	Sun Sep  9 10:45:43 2001
+++ linux-2.4.19-pre3/drivers/net/declance.c	Mon Mar 11 14:13:28 2002
@@ -79,6 +79,7 @@
 #include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <linux/etherdevice.h>
 
@@ -88,9 +89,6 @@
 #endif
 static int type;
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -920,7 +918,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_BE;
+	u32 crc;
 
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -945,19 +943,7 @@
 		if (!(*addrs & 1))
 			continue;
 
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++)
-			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test) {
-					crc = crc ^ poly;
-				}
-			}
-
+		crc = ether_crc(6, addrs);
 		crc = crc >> 26;
 		mcast_table[crc >> 3] |= 1 << (crc & 0xf);
 	}
diff -urN linux-2.4.19-pre2/drivers/net/depca.c linux-2.4.19-pre3/drivers/net/depca.c
--- linux-2.4.19-pre2/drivers/net/depca.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre3/drivers/net/depca.c	Mon Mar 11 14:13:28 2002
@@ -228,6 +228,8 @@
 			   by <peterd@pnd-pc.demon.co.uk>
       0.53    12-Jan-01	  Release resources on failure, bss tidbits
       			   by acme@conectiva.com.br
+      0.54    08-Nov-01	  use library crc32 functions
+      			   by Matt_Domsch@dell.com
 
     =========================================================================
 */
@@ -245,6 +247,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -296,9 +299,6 @@
 #define RX_BUFF_SZ	1536            /* Buffer size for each Rx buffer */
 #define TX_BUFF_SZ	1536            /* Buffer size for each Tx buffer */
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
 ** EISA bus defines
 */
@@ -1225,7 +1225,7 @@
   char *addrs;
   int i, j, bit, byte;
   u16 hashcode;
-  s32 crc, poly = CRC_POLYNOMIAL_BE;
+  u32 crc;
 
   if (dev->flags & IFF_ALLMULTI) {         /* Set all multicast bits */
     for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
@@ -1240,13 +1240,7 @@
       addrs=dmi->dmi_addr;
       dmi=dmi->next;
       if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
-	crc = 0xffffffff;                  /* init CRC for each address */
-	for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-	                                   /* process each address bit */ 
-	  for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
-	    crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
-	  }
-	}
+        crc = ether_crc(ETH_ALEN, addrs);
 	hashcode = (crc & 1);              /* hashcode is 6 LSb of CRC ... */
 	for (j=0;j<5;j++) {                /* ... in reverse order. */
 	  hashcode = (hashcode << 1) | ((crc>>=1) & 1);
diff -urN linux-2.4.19-pre2/drivers/net/dl2k.c linux-2.4.19-pre3/drivers/net/dl2k.c
--- linux-2.4.19-pre2/drivers/net/dl2k.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/dl2k.c	Mon Mar 11 14:13:28 2002
@@ -86,7 +86,6 @@
 static int find_miiphy (struct net_device *dev);
 static int parse_eeprom (struct net_device *dev);
 static int read_eeprom (long ioaddr, int eep_addr);
-static unsigned get_crc (unsigned char *p, int len);
 static int mii_wait_link (struct net_device *dev, int wait);
 static int mii_set_media (struct net_device *dev);
 static int mii_get_media (struct net_device *dev);
@@ -341,7 +340,7 @@
 	}
 
 	/* Check CRC */
-	crc = ~get_crc (sromdata, 256 - 4);
+ 	crc = ~ether_crc_le(256-4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -993,23 +992,6 @@
 	return 0;
 }
 
-#define CRC_POLY 0xedb88320
-static unsigned
-get_crc (unsigned char *p, int len)
-{
-	int bit;
-	unsigned char byte;
-	unsigned crc = 0xffffffff;
-
-	while (--len >= 0) {
-		byte = *p++;
-		for (bit = 0; bit < 8; bit++, byte >>= 1) {
-			crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
-		}
-	}
-	return crc;
-}
-
 static void
 set_multicast (struct net_device *dev)
 {
@@ -1039,7 +1021,7 @@
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
 				i++, mclist=mclist->next) {
-			crc = get_crc (mclist->dmi_addr, ETH_ALEN);
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
 			for (index=0, bit=0; bit<6; bit++, crc<<=1) {
 				if (crc & 0x80000000) index |= 1 << bit;
 			}
diff -urN linux-2.4.19-pre2/drivers/net/dl2k.h linux-2.4.19-pre3/drivers/net/dl2k.h
--- linux-2.4.19-pre2/drivers/net/dl2k.h	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/dl2k.h	Mon Mar 11 14:13:28 2002
@@ -26,6 +26,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
diff -urN linux-2.4.19-pre2/drivers/net/dmfe.c linux-2.4.19-pre3/drivers/net/dmfe.c
--- linux-2.4.19-pre2/drivers/net/dmfe.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/dmfe.c	Mon Mar 11 14:13:28 2002
@@ -84,6 +84,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/crc32.h>
 
 #include <asm/processor.h>
 #include <asm/bitops.h>
@@ -287,72 +288,6 @@
 static u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
 				   4: TX pause packet */
 
-unsigned long CrcTable[256] = {
-	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
-	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
-	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
-	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
-	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
-	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
-	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
-	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
-	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
-	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
-	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
-	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
-	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
-	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
-	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
-	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
-	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
-	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
-	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
-	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
-	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
-	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
-	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
-	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
-	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
-	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
-	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
-	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
-	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
-	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
-	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
-	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
-	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
-	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
-	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
-	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
-	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
-	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
-	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
-	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
-	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
-	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
-	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
-	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
-	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
-	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
-	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
-	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
-	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
-	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
-	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
-	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
-	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
-	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
-	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
-	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
-	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
-	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
-	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
-	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
-	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
-	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
-	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
-	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
-};
 
 /* function declaration ------------------------------------- */
 static int dmfe_open(struct DEVICE *);
@@ -381,7 +316,7 @@
 static void dmfe_dynamic_reset(struct DEVICE *);
 static void dmfe_free_rxbuffer(struct dmfe_board_info *);
 static void dmfe_init_dm910x(struct DEVICE *);
-static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
 static void dmfe_parse_srom(struct dmfe_board_info *);
 static void dmfe_program_DM9801(struct dmfe_board_info *, int);
 static void dmfe_program_DM9802(struct dmfe_board_info *);
@@ -1850,18 +1785,11 @@
  *		0 : return the normal CRC (for Hash Table index)
  */
 
-unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
 {
-	unsigned long Crc = 0xffffffff;
-
-	while (Len--) {
-		Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
-	}
-
-	if (flag)
-		return ~Crc;
-	else
-		return Crc;
+	u32 crc = ether_crc_le(Len, Data);
+	if (flag) crc = ~crc;
+	return crc;
 }
 
 
diff -urN linux-2.4.19-pre2/drivers/net/epic100.c linux-2.4.19-pre3/drivers/net/epic100.c
--- linux-2.4.19-pre2/drivers/net/epic100.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/epic100.c	Mon Mar 11 14:13:28 2002
@@ -131,6 +131,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1302,27 +1303,6 @@
    new frame, not around filling ep->setup_frame.  This is non-deterministic
    when re-entered but still correct. */
 
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
diff -urN linux-2.4.19-pre2/drivers/net/ewrk3.c linux-2.4.19-pre3/drivers/net/ewrk3.c
--- linux-2.4.19-pre2/drivers/net/ewrk3.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre3/drivers/net/ewrk3.c	Mon Mar 11 14:13:28 2002
@@ -132,6 +132,7 @@
    <kenneth@bbs.sas.ntu.ac.sg>.
    0.42    22-Apr-96      Fix alloc_device() bug <jari@markkus2.fimr.fi>
    0.43    16-Aug-96      Update alloc_device() to conform to de4x5.c
+   0.44    08-Nov-01      use library crc32 functions <Matt_Domsch@dell.com>
 
    =========================================================================
  */
@@ -148,6 +149,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -207,9 +209,6 @@
 #define EISA_SLOT_INC 0x1000
 #endif
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 #define QUEUE_PKT_TIMEOUT (1*HZ)	/* Jiffies */
 
 /*
@@ -1174,10 +1173,10 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	u_long iobase = dev->base_addr;
 	int i;
-	char *addrs, j, bit, byte;
+	char *addrs, bit, byte;
 	short *p = (short *) lp->mctbl;
 	u16 hashcode;
-	s32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	spin_lock_irq(&lp->hw_lock);
 
@@ -1219,13 +1218,7 @@
 			addrs = dmi->dmi_addr;
 			dmi = dmi->next;
 			if ((*addrs & 0x01) == 1) {	/* multicast address? */
-				crc = 0xffffffff;	/* init CRC for each address */
-				for (byte = 0; byte < ETH_ALEN; byte++) {	/* for each address byte */
-					/* process each address bit */
-					for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-						crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
-					}
-				}
+				crc = ether_crc_le(ETH_ALEN, addrs);
 				hashcode = crc & ((1 << 9) - 1);	/* hashcode is 9 LSb of CRC */
 
 				byte = hashcode >> 3;	/* bit[3-8] -> byte in filter */
diff -urN linux-2.4.19-pre2/drivers/net/fealnx.c linux-2.4.19-pre3/drivers/net/fealnx.c
--- linux-2.4.19-pre2/drivers/net/fealnx.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/fealnx.c	Mon Mar 11 14:13:28 2002
@@ -84,6 +84,7 @@
 #include <linux/init.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -439,7 +440,6 @@
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -1726,26 +1726,6 @@
 	return &np->stats;
 }
 
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-	}
-
-	return crc;
-}
-
-
 static void set_rx_mode(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/gmac.c linux-2.4.19-pre3/drivers/net/gmac.c
--- linux-2.4.19-pre2/drivers/net/gmac.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/gmac.c	Mon Mar 11 14:13:28 2002
@@ -16,6 +16,8 @@
  *  - PHY updates
  * BenH <benh@kernel.crashing.org> - 08/08/2001
  * - Add more PHYs, fixes to sleep code
+ * Matt Domsch <Matt_Domsch@dell.com> - 11/12/2001
+ * - use library crc32 functions
  */
 
 #include <linux/module.h>
@@ -33,6 +35,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -1000,14 +1003,13 @@
  * Configure promisc mode and setup multicast hash table
  * filter
  */
-#define CRC_POLY	0xedb88320
 static void
 gmac_set_multicast(struct net_device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 	struct dev_mc_list *dmi = dev->mc_list;
 	int i,j,k,b;
-	unsigned long crc;
+	u32 crc;
 	int multicast_hash = 0;
 	int multicast_all = 0;
 	int promisc = 0;
@@ -1030,17 +1032,7 @@
 			hash_table[i] = 0;
 
 	    	for (i = 0; i < dev->mc_count; i++) {
-			crc = ~0;
-			for (j = 0; j < 6; ++j) {
-			    b = dmi->dmi_addr[j];
-			    for (k = 0; k < 8; ++k) {
-				if ((crc ^ b) & 1)
-				    crc = (crc >> 1) ^ CRC_POLY;
-				else
-				    crc >>= 1;
-				b >>= 1;
-			    }
-			}
+			crc = ether_crc_le(6, dmi->dmi_addr);
 			j = crc >> 24;	/* bit number in multicast_filter */
 			hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
 			dmi = dmi->next;
diff -urN linux-2.4.19-pre2/drivers/net/ioc3-eth.c linux-2.4.19-pre3/drivers/net/ioc3-eth.c
--- linux-2.4.19-pre2/drivers/net/ioc3-eth.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/ioc3-eth.c	Mon Mar 11 14:13:28 2002
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 
 #ifdef CONFIG_SERIAL
 #include <linux/serial.h>
@@ -1723,27 +1724,16 @@
  * Given a multicast ethernet address, this routine calculates the
  * address's bit index in the logical address filter mask
  */
-#define CRC_MASK        0xedb88320
 
 static inline unsigned int
 ioc3_hash(const unsigned char *addr)
 {
 	unsigned int temp = 0;
 	unsigned char byte;
-	unsigned int crc;
-	int bits, len;
+	u32 crc;
+	int bits;
 
-	len = ETH_ALEN;
-	for (crc = ~0; --len >= 0; addr++) {
-		byte = *addr;
-		for (bits = 8; --bits >= 0; ) {
-			if ((byte ^ crc) & 1)
-				crc = (crc >> 1) ^ CRC_MASK;
-			else
-				crc >>= 1;
-			byte >>= 1;
-		}
-	}
+	crc = ether_crc_le(ETH_ALEN, addr);
 
 	crc &= 0x3f;    /* bit reverse lowest 6 bits for hash index */
 	for (bits = 6; --bits >= 0; ) {
diff -urN linux-2.4.19-pre2/drivers/net/irda/Config.in linux-2.4.19-pre3/drivers/net/irda/Config.in
--- linux-2.4.19-pre2/drivers/net/irda/Config.in	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/irda/Config.in	Mon Mar 11 14:13:28 2002
@@ -24,7 +24,9 @@
 dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR  $CONFIG_IRDA
 dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
-dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA
+if [ "$CONFIG_MIPS" = "y" ]; then
+   dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA
+fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
 dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA
diff -urN linux-2.4.19-pre2/drivers/net/irda/ali-ircc.c linux-2.4.19-pre3/drivers/net/irda/ali-ircc.c
--- linux-2.4.19-pre2/drivers/net/irda/ali-ircc.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/irda/ali-ircc.c	Mon Mar 11 14:13:28 2002
@@ -291,15 +291,13 @@
         self->io.fifo_size = 16;		/* SIR: 16, FIR: 32 Benjamin 2000/11/1 */
 	
 	/* Reserve the ioports that we need */
-	ret = check_region(self->io.fir_base, self->io.fir_ext);
-	if (ret < 0) { 
+	if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
 		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
 			self->io.fir_base);
 		dev_self[i] = NULL;
 		kfree(self);
 		return -ENODEV;
 	}
-	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&self->qos);
diff -urN linux-2.4.19-pre2/drivers/net/irda/irda-usb.c linux-2.4.19-pre3/drivers/net/irda/irda-usb.c
--- linux-2.4.19-pre2/drivers/net/irda/irda-usb.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/irda/irda-usb.c	Mon Mar 11 14:13:28 2002
@@ -378,10 +378,17 @@
 		return 0;
 	}
 
-	/* Make room for IrDA-USB header (note skb->len += USB_IRDA_HEADER) */
-	if (skb_cow(skb, USB_IRDA_HEADER)) {
-		dev_kfree_skb(skb);
-		return 0;
+	/* Make sure there is room for IrDA-USB header. The actual
+	 * allocation will be done lower in skb_push().
+	 * Also, we don't use directly skb_cow(), because it require
+	 * headroom >= 16, which force unnecessary copies - Jean II */
+	if (skb_headroom(skb) < USB_IRDA_HEADER) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");
+		if (skb_cow(skb, USB_IRDA_HEADER)) {
+			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");
+			dev_kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	spin_lock_irqsave(&self->lock, flags);
@@ -432,7 +439,7 @@
 #ifdef IU_USB_MIN_RTT
 			/* Factor in USB delays -> Get rid of udelay() that
 			 * would be lost in the noise - Jean II */
-			diff -= IU_USB_MIN_RTT;
+			diff += IU_USB_MIN_RTT;
 #endif /* IU_USB_MIN_RTT */
 			if (diff < 0)
 				diff += 1000000;
@@ -848,8 +855,8 @@
 	/* Submit the idle URB to replace the URB we've just received */
 	irda_usb_submit(self, skb, self->idle_rx_urb);
 	/* Recycle Rx URB : Now, the idle URB is the present one */
-	self->idle_rx_urb = purb;
 	purb->context = NULL;
+	self->idle_rx_urb = purb;
 }
 
 /*------------------------------------------------------------------*/
@@ -952,13 +959,17 @@
 	/* Allow IrLAP to send data to us */
 	netif_start_queue(netdev);
 
+	/* We submit all the Rx URB except for one that we keep idle.
+	 * Need to be initialised before submitting other USBs, because
+	 * in some cases as soon as we submit the URBs the USB layer
+	 * will trigger a dummy receive - Jean II */
+	self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
+	self->idle_rx_urb->context = NULL;
+
 	/* Now that we can pass data to IrLAP, allow the USB layer
 	 * to send us some data... */
 	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
 		irda_usb_submit(self, NULL, &(self->rx_urb[i]));
-	/* Note : we submit all the Rx URB except for one - Jean II */
-	self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
-	self->idle_rx_urb->context = NULL;
 
 	/* Ready to play !!! */
 	MOD_INC_USE_COUNT;
diff -urN linux-2.4.19-pre2/drivers/net/lance.c linux-2.4.19-pre3/drivers/net/lance.c
--- linux-2.4.19-pre2/drivers/net/lance.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre3/drivers/net/lance.c	Mon Mar 11 14:13:28 2002
@@ -354,7 +354,7 @@
    board probes now that kmalloc() can allocate ISA DMA-able regions.
    This also allows the LANCE driver to be used as a module.
    */
-int lance_probe(struct net_device *dev)
+int __init lance_probe(struct net_device *dev)
 {
 	int *port, result;
 
diff -urN linux-2.4.19-pre2/drivers/net/mace.c linux-2.4.19-pre3/drivers/net/mace.c
--- linux-2.4.19-pre2/drivers/net/mace.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/mace.c	Mon Mar 11 14:13:28 2002
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -549,17 +550,12 @@
     return &p->stats;
 }
 
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY	0xedb88320
-
 static void mace_set_multicast(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
     volatile struct mace *mb = mp->mace;
-    int i, j, k, b;
-    unsigned long crc;
+    int i, j;
+    u32 crc;
 
     mp->maccc &= ~PROM;
     if (dev->flags & IFF_PROMISC) {
@@ -575,17 +571,7 @@
 	    for (i = 0; i < 8; i++)
 		multicast_filter[i] = 0;
 	    for (i = 0; i < dev->mc_count; i++) {
-		crc = ~0;
-		for (j = 0; j < 6; ++j) {
-		    b = dmi->dmi_addr[j];
-		    for (k = 0; k < 8; ++k) {
-			if ((crc ^ b) & 1)
-			    crc = (crc >> 1) ^ CRC_POLY;
-			else
-			    crc >>= 1;
-			b >>= 1;
-		    }
-		}
+	        crc = ether_crc_le(6, dmi->dmi_addr);
 		j = crc >> 26;	/* bit number in multicast_filter */
 		multicast_filter[j >> 3] |= 1 << (j & 7);
 		dmi = dmi->next;
diff -urN linux-2.4.19-pre2/drivers/net/macmace.c linux-2.4.19-pre3/drivers/net/macmace.c
--- linux-2.4.19-pre2/drivers/net/macmace.c	Thu Apr 12 12:15:25 2001
+++ linux-2.4.19-pre3/drivers/net/macmace.c	Mon Mar 11 14:13:28 2002
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -539,17 +540,12 @@
 	return &p->stats;
 }
 
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY	0xedb88320
-
 static void mace68k_set_multicast(struct net_device *dev)
 {
 	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
 	volatile struct mace *mb = mp->mace;
 	int i, j, k, b;
-	unsigned long crc;
+	u32 crc;
 
 	mp->maccc &= ~PROM;
 	if (dev->flags & IFF_PROMISC)
@@ -570,19 +566,7 @@
 				multicast_filter[i] = 0;
 			for (i = 0; i < dev->mc_count; i++)
 			{
-				crc = ~0;
-				for (j = 0; j < 6; ++j)
-				{
-					b = dmi->dmi_addr[j];
-					for (k = 0; k < 8; ++k)
-					{
-						if ((crc ^ b) & 1)
-							crc = (crc >> 1) ^ CRC_POLY;
-						else
-							crc >>= 1;
-						b >>= 1;
-					}
-				}
+				crc = ether_crc_le(6, dmi->dmi_addr);
 				j = crc >> 26;	/* bit number in multicast_filter */
 				multicast_filter[j >> 3] |= 1 << (j & 7);
 				dmi = dmi->next;
diff -urN linux-2.4.19-pre2/drivers/net/meth.c linux-2.4.19-pre3/drivers/net/meth.c
--- linux-2.4.19-pre2/drivers/net/meth.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/meth.c	Wed Dec 31 16:00:00 1969
@@ -1,673 +0,0 @@
-/*
- * meth.c -- O2 Builtin 10/100 Ethernet driver, that doesn't work at the moment
- *
- * Copyright (C) 2001 Ilya Volynets
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- */
-
-#ifndef __KERNEL__
-#  define __KERNEL__
-#endif
-
-#ifndef MFE_DEBUG
-#define MFE_DEBUG 0
-#endif
-
-#if MFE_DEBUG>=1
-#define DPRINTK(str,args...) printk (KERN_DEBUG "meth: %s: " str, __FUNCTION__ , ## args)
-#define MFE_RX_DEBUG 2
-#else
-#define DPRINTK(str,args...)
-#define MFE_RX_DEBUG 0
-#endif
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/delay.h>
-#include <linux/malloc.h> /* kmalloc() */
-#include <linux/errno.h>  /* error codes */
-#include <linux/types.h>  /* size_t */
-#include <linux/interrupt.h> /* mark_bh */
-#include <linux/pci.h>
-
-#include <linux/in.h>
-#include <linux/netdevice.h>   /* struct device, and other headers */
-#include <linux/etherdevice.h> /* eth_type_trans */
-#include <linux/ip.h>          /* struct iphdr */
-#include <linux/tcp.h>         /* struct tcphdr */
-#include <linux/skbuff.h>
-#include <linux/mii.h> /*MII definitions */
-
-#include <asm/ip32/crime.h>
-#include <asm/ip32/mace.h>
-#include <asm/ip32/ip32_ints.h>
-
-#include "meth.h"
-
-#include <linux/in6.h>
-#include <asm/checksum.h>
-
-static const char *version="meth.c: Ilya Volynets (ilya@theIlya.com)";
-static const char *meth_str="SGI O2 Fast Ethernet";
-MODULE_AUTHOR("Ilya Volynets");
-MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver");
-
-/* This is a load-time options */
-/*static int eth = 0;
-MODULE_PARM(eth, "i");*/
-/*
-#ifdef HAVE_TX_TIMEOUT
-static int timeout = 0;
-MODULE_PARM(timeout, "i");
-#endif
-*/
-int meth_eth;
-
-
-/*
- * This structure is private to each device. It is used to pass
- * packets in and out, so there is place for a packet
- */
-
-typedef struct meth_private {
-    struct net_device_stats stats;
-	volatile struct meth_regs *regs;
-	u64 mode; /* in-memory copy of MAC control register */
-	int  phy_addr; /* address of phy, used by mdio_* functions, initialized in mdio_probe*/
-	tx_packet *tx_ring;
-	dma_addr_t tx_ring_dma;
-	int free_space;
-	struct sk_buff *tx_skbs[TX_RING_ENTRIES];
-	dma_addr_t      tx_skb_dmas[TX_RING_ENTRIES];
-	int tx_read,tx_write;
-
-	rx_packet *rx_ring[RX_RING_ENTRIES];
-	dma_addr_t rx_ring_dmas[RX_RING_ENTRIES];
-	int rx_write;
-
-    spinlock_t meth_lock;
-} meth_private;
-
-extern struct net_device meth_devs[];
-void meth_tx_timeout (struct net_device *dev);
-void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
-        
-/* global, initialized in ip32-setup.c */
-char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
-
-static inline void load_eaddr(struct net_device *dev,
-				   volatile struct meth_regs *regs)
-{
-	int i;
-	DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-		(int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
-		(int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
-	//memcpy(dev->dev_addr,o2meth_eaddr+2,6);
-	for (i=0; i<6; i++)
-		dev->dev_addr[i]=o2meth_eaddr[i];
-	regs->mac_addr= //dev->dev_addr[0]|(dev->dev_addr[1]<<8)|
-					//dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)|
-					//dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40);
-	(*(u64*)o2meth_eaddr)>>16;
-	DPRINTK("MAC, finally is %0lx\n",regs->mac_addr);
-}
-
-/*
- *Waits for BUSY status of mdio bus to clear
- */
-#define WAIT_FOR_PHY(___regs, ___rval)			\
-	while((___rval=___regs->phy_data)&MDIO_BUSY){	\
-		udelay(25);								\
-	}
-/*read phy register, return value read */
-static int mdio_read(meth_private *priv,int phyreg)
-{
-	volatile meth_regs* regs=priv->regs;
-	volatile u32 rval;
-	WAIT_FOR_PHY(regs,rval)
-	regs->phy_registers=(priv->phy_addr<<5)|(phyreg&0x1f);
-	udelay(25);
-	regs->phy_trans_go=1;
-	udelay(25);
-	WAIT_FOR_PHY(regs,rval)
-	return rval&MDIO_DATA_MASK;
-}
-
-/*write phy register */
-static void mdio_write(meth_private* priv,int pfyreg,int val)
-{
-	volatile meth_regs* regs=priv->regs;
-	int rval;
-///	DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg);
-///	spin_lock_irq(&priv->meth_lock);
-	WAIT_FOR_PHY(regs,rval)
-	regs->phy_registers=(priv->phy_addr<<5)|(pfyreg&0x1f);
-	regs->phy_data=val;
-	udelay(25);
-	WAIT_FOR_PHY(regs,rval)
-///	spin_unlock_irq(&priv->meth_lock);
-}
-
-/* Modify phy register using given mask and value */
-static void mdio_update(meth_private* priv,int phyreg, int val, int mask)
-{
-	int rval;
-	DPRINTK("RMW value %i to PHY register %i with mask %i\n",val,phyreg,mask);
-	rval=mdio_read(priv,phyreg);
-	rval=(rval&~mask)|(val&mask);
-	mdio_write(priv,phyreg,rval);
-}
-
-/* handle errata data on MDIO bus */
-//static void mdio_errata(meth_private *priv)
-//{
-	/* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */
-//}
-static int mdio_probe(meth_private *priv)
-{
-	int i, p2, p3;
-	DPRINTK("Detecting PHY kind\n");
-	/* check if phy is detected already */
-	if(priv->phy_addr>=0&&priv->phy_addr<32)
-		return 0;
-	spin_lock_irq(priv->meth_lock);
-	for (i=0;i<32;++i){
-		priv->phy_addr=(char)i;
-		p2=mdio_read(priv,2);
-#ifdef MFE_DEBUG
-		p3=mdio_read(priv,3);
-		switch ((p2<<12)|(p3>>4)){
-			case PHY_QS6612X:
-				DPRINTK("PHY is QS6612X\n");
-				break;
-			case PHY_ICS1889:
-				DPRINTK("PHY is ICS1889\n");
-				break;
-			case PHY_ICS1890:
-				DPRINTK("PHY is ICS1890\n");
-				break;
-			case PHY_DP83840:
-				DPRINTK("PHY is DP83840\n");
-				break;
-		}
-#endif
-		if(p2!=0xffff&&p2!=0x0000){
-			DPRINTK("PHY code: %x\n",(p2<<12)|(p3>>4));
-			break;
-		}
-	}
-	spin_unlock_irq(priv->meth_lock);
-	if(priv->phy_addr<32) {
-		return 0;
-	}
-	DPRINTK("Oopsie! PHY is not known!\n");
-	priv->phy_addr=-1;
-	return -ENODEV;
-}
-
-static int meth_init_tx_ring(meth_private *priv)
-{
-	/* Init TX ring */
-	DPRINTK("Initializing TX ring\n");
-	priv->tx_ring=(tx_packet*)pci_alloc_consistent(NULL,TX_RING_BUFFER_SIZE,&(priv->tx_ring_dma));
-	if(!priv->tx_ring)
-		return -ENOMEM;
-	memset(priv->tx_ring,0,TX_RING_BUFFER_SIZE);
-	priv->regs->tx_ring_base=priv->tx_ring_dma;
-	priv->free_space=TX_RING_ENTRIES;
-	/* Now init ksb save area */
-	memset(priv->tx_skbs,0,sizeof(priv->tx_skbs));
-	memset(priv->tx_skb_dmas,0,sizeof(priv->tx_skb_dmas));
-	DPRINTK("Done with TX ring init\n");
-	return 0;
-}
-
-static int meth_init_rx_ring(meth_private *priv)
-{
-	int i;
-	DPRINTK("Initializing RX ring\n");
-	for(i=0;i<RX_RING_ENTRIES;i++){
-		DPRINTK("\t1:\t%i\n",i);
-		/*if(!(priv->rx_ring[i]=get_free_page(GFP_KERNEL)))
-			return -ENOMEM;
-		DPRINTK("\t2:\t%i\n",i);*/
-		priv->rx_ring[i]=(rx_packet*)pci_alloc_consistent(NULL,METH_RX_BUFF_SIZE,&(priv->rx_ring_dmas[i]));
-		/* I'll need to re-sync it after each RX */
-		DPRINTK("\t2:\t%i\n",i);
-		priv->regs->rx_fifo=priv->rx_ring_dmas[i];
-	}
-	DPRINTK("Done with RX ring\n");
-	return 0;
-}
-static void meth_free_tx_ring(meth_private *priv)
-{
-	pci_free_consistent(NULL,TX_RING_BUFFER_SIZE,priv->tx_ring,priv->tx_ring_dma);
-}
-static void meth_free_rx_ring(meth_private *priv)
-{
-	int i;
-	for(i=0;i<RX_RING_ENTRIES;i++)
-		pci_free_consistent(NULL,TX_RING_BUFFER_SIZE,priv->rx_ring[i],priv->rx_ring_dmas[i]);
-}
-
-/*============End Helper Routines=====================*/
-
-/*
- * Open and close
- */
-
-int meth_open(struct net_device *dev)
-{
-	meth_private *priv=dev->priv;
-	volatile meth_regs *regs=priv->regs;
-    MOD_INC_USE_COUNT;
-	/* Start DMA */
-	regs->dma_ctrl|=
-		METH_DMA_TX_EN|/*METH_DMA_TX_INT_EN|*/
-		METH_DMA_RX_EN|METH_DMA_RX_INT_EN;
-
-	if(request_irq(dev->irq,meth_interrupt,SA_SHIRQ,meth_str,dev)){
-		printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-    netif_start_queue(dev);
-	DPRINTK("Opened... DMA control=0x%08lx\n", regs->dma_ctrl);
-    return 0;
-}
-
-int meth_release(struct net_device *dev)
-{
-    netif_stop_queue(dev); /* can't transmit any more */
-	/* shut down dma */
-	((meth_private*)(dev->priv))->regs->dma_ctrl&=
-		~(METH_DMA_TX_EN|METH_DMA_TX_INT_EN|
-		METH_DMA_RX_EN|METH_DMA_RX_INT_EN);
-	free_irq(dev->irq, dev);
-    MOD_DEC_USE_COUNT;
-    return 0;
-}
-
-/*
- * Configuration changes (passed on by ifconfig)
- */
-int meth_config(struct net_device *dev, struct ifmap *map)
-{
-    if (dev->flags & IFF_UP) /* can't act on a running interface */
-        return -EBUSY;
-
-    /* Don't allow changing the I/O address */
-    if (map->base_addr != dev->base_addr) {
-        printk(KERN_WARNING "meth: Can't change I/O address\n");
-        return -EOPNOTSUPP;
-    }
-
-    /* Allow changing the IRQ */
-    if (map->irq != dev->irq) {
-        printk(KERN_WARNING "meth: Can't change IRQ\n");
-        return -EOPNOTSUPP;
-    }
-	DPRINTK("Configured\n");
-
-    /* ignore other fields */
-    return 0;
-}
-
-/*
- * Receive a packet: retrieve, encapsulate and pass over to upper levels
- */
-void meth_rx(struct net_device* dev)
-{
-    struct sk_buff *skb;
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-	rx_packet *rxb;
-	DPRINTK("RX...\n");
-	while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
-		int len=rxb->status.parsed.rx_len;
-		DPRINTK("\tpriv->tx_write=%i\n",priv->rx_write);
-		if(!(rxb->status.raw&METH_RX_STATUS_ERRORS)){
-			DPRINTK("Packet had no errors...\n");
-			skb=alloc_skb(len+2,GFP_ATOMIC);/* Should be atomic -- we are in interrupt */
-			if(!skb){
-				/* Ouch! No memory! Drop packet on the floor */
-				DPRINTK("!!!>>>Ouch! Not enough Memory for RX buffer!\n");
-				priv->stats.tx_dropped++;
-			} else {
-				DPRINTK("And there was no problem getting new skb...\n");
-				skb_reserve(skb, 2); /* align IP on 16B boundary */  
-    			memcpy(skb_put(skb, len), rxb->buf, len);
-			    /* Write metadata, and then pass to the receive level */
-			    skb->dev = dev;
-			    skb->protocol = eth_type_trans(skb, dev);
-				//skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
-			    priv->stats.rx_packets++;
-				DPRINTK("We are about to pass packet up\n");
-    			netif_rx(skb);
-				DPRINTK("There we go... Whew...\n");
-			}
-		}
-		rxb->status.raw=0;
-		priv->regs->rx_fifo=priv->rx_ring_dmas[priv->rx_write];
-		priv->rx_write=(priv->rx_write+1)&(RX_RING_ENTRIES-1);
-	}
-}
-
-void meth_tx_cleanup(struct net_device* dev, int rptr)
-{
-	meth_private *priv=dev->priv;
-	//volatile meth_regs* regs=priv->regs;
-	tx_packet* status;
-	struct sk_buff* skb;
-	DPRINTK("TX...\n");
-	spin_lock(&priv->meth_lock);
-	priv->regs->dma_ctrl&=~(METH_DMA_TX_INT_EN);
-	while(priv->tx_read!=rptr){
-		skb=priv->tx_skbs[priv->tx_read];
-		status=&priv->tx_ring[priv->tx_read];
-		if(!status->header.res.sent)
-			break;
-		if(status->header.raw&METH_TX_STATUS_DONE){
-			priv->stats.tx_packets++;
-			priv->stats.tx_bytes+=skb->len;
-		}
-        dev_kfree_skb(skb);
-		status->header.raw=0;
-		priv->tx_read=(priv->tx_read+1)&(TX_RING_ENTRIES-1);
-	}
-	spin_unlock(priv->meth_lock);
-	netif_wake_queue(dev);
-}
-
-/*
- * The typical interrupt entry point
- */
-void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
-{
-    struct meth_private *priv;
-	//volatile meth_regs* regs;
-	union {
-		u32	reg; /*Whole status register */
-		struct {
-			u32			:	2,
-				rx_seq	:	5,
-				tx_read	:	9,
-				
-				rx_read	:	8,
-				int_mask:	8;
-		} parsed;
-	} status;
-    /*
-     * As usual, check the "device" pointer for shared handlers.
-     * Then assign "struct device *dev"
-     */
-    struct net_device *dev = (struct net_device *)dev_id;
-    /* ... and check with hw if it's really ours */
-
-    if (!dev /*paranoid*/ ) return;
-
-    /* Lock the device */
-    priv = (struct meth_private *) dev->priv;
-    spin_lock(&priv->meth_lock);
-
-    status.reg = priv->regs->int_flags;
-	priv->regs->int_flags=status.reg&0xff; /* clear interrupts */
-	DPRINTK("Interrupt, status %08x...\n",status.reg);
-    if (status.parsed.int_mask & METH_INT_RX_THRESHOLD) {
-        /* send it to meth_rx for handling */
-        meth_rx(dev);
-    }
-    if (status.parsed.int_mask & (METH_INT_TX_EMPTY|METH_INT_TX_PKT)) {
-        /* a transmission is over: free the skb */
-		meth_tx_cleanup(dev,status.parsed.tx_read);
-    }
-	/* check for errors too... */
-
-	DPRINTK("Interrupt handling done...\n");
-    /* Unlock the device and we are done */
-    spin_unlock(&priv->meth_lock);
-}
-
-/*
- * Transmits packets that fit into TX describtor (are <=120B)
- */
-static void meth_tx_short_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	int len=(skb->len<ETH_ZLEN)?ETH_ZLEN:skb->len;
-	DPRINTK("Short packet... \n");
-	/* amybe I should set whole thing to 0 first... */
-	memcpy(desc->data.dt+(120-len),skb->data,skb->len);
-	if(skb->len<len)
-		memset(desc->data.dt+120-len+skb->len,0,len-skb->len);
-	desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16);
-	DPRINTK("desc=%016lx\n",desc->header.raw);
-}
-#define TX_CATBUF1 BIT(25)
-static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	void *data=skb->data;
-	int len=(u64)data&0x7;
-	dma_addr_t catbuf;
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1);
-	if(len){
-		memcpy(desc->data.dt+(120-len),data,len);
-		desc->header.raw|=(128-len)<<16;
-	}
-	data+=len;
-	/* I'll just pretend I know for sure that pci_unmap_single is NOP */
-	catbuf=pci_map_single(NULL,data,skb->len-len,PCI_DMA_TODEVICE);
-	desc->data.cat_buf[0].raw=catbuf|((skb->len-len-1)<<31);
-}
-#define TX_CATBUF2 BIT(26)
-static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb)
-{
-	tx_packet *desc=&priv->tx_ring[priv->tx_write];
-	void *data=skb->data;
-	int len=(u64)data&0x7;
-	dma_addr_t catbuf1,catbuf2;
-	desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1);
-	if(len){
-		memcpy(desc->data.dt+(120-len),data,len);
-		desc->header.raw|=(128-len)<<16;
-	}
-	data+=len;
-	/* I'll just pretend I know for sure that pci_unmap_single is NOP */
-	catbuf1=pci_map_single(NULL,data,skb->len-len,PCI_DMA_TODEVICE);
-	desc->data.cat_buf[0].raw=catbuf1|((skb->len-len-1)<<31);
-	len=(u64)data&0xFFF;
-	data+=len;
-	catbuf2=pci_map_single(NULL,data,skb->len-((u64)data-(u64)skb->data),PCI_DMA_TODEVICE);
-	desc->data.cat_buf[1].raw=catbuf2|((skb->len-((u64)data-(u64)skb->data))<<31);
-}
-/*
- * Transmit a packet (called by the kernel)
- */
-int meth_tx(struct sk_buff *skb, struct net_device *dev)
-{
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-
-    spin_lock(&priv->meth_lock);
-	DPRINTK("Transmitting data...\n");
-	if(skb->len<=120) /* Whole thing fits into descriptor */
-		meth_tx_short_prepare(priv,skb);
-	else if(((u64)(skb->data)&0xFFF)<skb->len) /* Packet crosses page boundary */
-		meth_tx_2page_prepare(priv,skb);
-	else /* Packet is in one page */
-		meth_tx_1page_prepare(priv,skb);
-    dev->trans_start = jiffies; /* save the timestamp */
-
-    /* Remember the skb, so we can free it at interrupt time */
-    priv->tx_skbs[priv->tx_write] = skb;
-	priv->regs->tx_info.wptr=priv->tx_write;
-	priv->tx_write=(priv->tx_write+1)&(TX_RING_ENTRIES-1);
-
-	priv->regs->dma_ctrl|=METH_DMA_TX_INT_EN;
-
-	spin_unlock(&priv->meth_lock);
-
-    return 0;
-}
-
-/*
- * Deal with a transmit timeout.
- */
- /*
-void meth_tx_timeout (struct net_device *dev)
-{
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-
-    DPRINTK("Transmit timeout at %ld, latency %ld\n", jiffies,
-                    jiffies - dev->trans_start);
-    priv->status = meth_TX_INTR;
-    meth_interrupt(0, dev, NULL);
-    priv->stats.tx_errors++;
-    netif_wake_queue(dev);
-    return;
-}
-*/
-/*
- * Ioctl commands 
- */
-int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- 
-    DPRINTK("ioctl\n");
-    return 0;
-}
-
-/*
- * Return statistics to the caller
- */
-struct net_device_stats *meth_stats(struct net_device *dev)
-{
-    struct meth_private *priv = (struct meth_private *) dev->priv;
-    return &priv->stats;
-}
-
-/*
- * The init function (sometimes called probe).
- * It is invoked by register_netdev()
- */
-int meth_init(struct net_device *dev)
-{
-	meth_private *priv;
-	volatile meth_regs* regs;
-	int ret;
-    /* 
-     * Then, assign other fields in dev, using ether_setup() and some
-     * hand assignments
-     */
-    ether_setup(dev); /* assign some of the fields */
-
-    dev->open            = meth_open;
-    dev->stop            = meth_release;
-    dev->set_config      = meth_config;
-    dev->hard_start_xmit = meth_tx;
-    dev->do_ioctl        = meth_ioctl;
-    dev->get_stats       = meth_stats;
-/*#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout     = meth_tx_timeout;
-    dev->watchdog_timeo = timeout;
-#endif*/
-	dev->irq			= MACE_ETHERNET_IRQ;
-    SET_MODULE_OWNER(dev);
-
-    /*
-     * Then, allocate the priv field. This encloses the statistics
-     * and a few private fields.
-     */
-    priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL);
-    if (priv == NULL)
-        return -ENOMEM;
-	dev->priv=priv;
-    memset(priv, 0, sizeof(struct meth_private));
-    spin_lock_init(& (struct meth_private *) (dev->priv)->meth_lock);
-    /*
-     * Make the usual checks: check_region(), probe irq, ...  -ENODEV
-     * should be returned if no device found.  No resource should be
-     * grabbed: this is done on open(). 
-     */
-	priv->regs=(meth_regs*)SGI_MFE;
-	dev->base_addr=SGI_MFE;
-
-	regs=(meth_regs*)SGI_MFE;
-
-	/* Reset card */
-	regs->mac_ctrl=SGI_MAC_RESET;
-	regs->mac_ctrl=0;
-	udelay(25);
-	DPRINTK("MAC control after reset: %016lx\n",regs->mac_ctrl);
-	printk("SGI O2 Fast Ethernet rev. %ld\n",regs->mac_ctrl>>29);
-
-	load_eaddr(dev,regs);
-	priv->phy_addr=-1; /* No phy is known yet... */
-	if(mdio_probe(priv)<0){
-		DPRINTK("Unable to find PHY\n");
-		return -ENODEV;
-	}
-	/* Should load some "errata", but later */
-	
-	/* Initial mode -- 100|Half-duplex|Acept normal packets */
-	priv->mode=METH_ACCEPT_MCAST|METH_100MBIT|METH_DEFAULT_IPG;
-	if(dev->flags|IFF_PROMISC)
-		priv->mode|=METH_PROMISC;
-	regs->mac_ctrl=priv->mode;
-
-	if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){
-		meth_free_tx_ring(priv);
-		meth_free_rx_ring(priv);
-		return ret;
-	}
-	/* Now set dma control, but don't enable DMA, yet */
-	priv->regs->dma_ctrl=(4<<METH_RX_OFFSET_SHIFT)|(RX_RING_ENTRIES<<METH_RX_DEPTH_SHIFT);
-    return 0;
-}
-
-/*
- * The devices
- */
-
-struct net_device meth_devs[1] = {
-    { init: meth_init, }  /* init, nothing more */
-};
-
-/*
- * Finally, the module stuff
- */
-
-int meth_init_module(void)
-{
-
-    int result, device_present = 0;
-
-	strcpy(meth_devs[0].name, "eth%d");
-
-	if ( (result = register_netdev(meth_devs)) )
-        printk("meth: error %i registering device \"%s\"\n",
-                   result, meth_devs->name);
-	else device_present++;
-#ifndef METH_DEBUG
-    EXPORT_NO_SYMBOLS;
-#endif
-
-    return device_present ? 0 : -ENODEV;
-}
-
-void meth_cleanup(void)
-{
-    kfree(meth_devs->priv);
-    unregister_netdev(meth_devs);
-    return;
-}
-
-module_init(meth_init_module);
-module_exit(meth_cleanup);
diff -urN linux-2.4.19-pre2/drivers/net/myri_sbus.c linux-2.4.19-pre3/drivers/net/myri_sbus.c
--- linux-2.4.19-pre2/drivers/net/myri_sbus.c	Fri Oct 19 08:32:28 2001
+++ linux-2.4.19-pre3/drivers/net/myri_sbus.c	Mon Mar 11 14:13:28 2002
@@ -800,9 +800,6 @@
 static struct net_device_stats *myri_get_stats(struct net_device *dev)
 { return &(((struct myri_eth *)dev->priv)->enet_stats); }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void myri_set_multicast(struct net_device *dev)
 {
 	/* Do nothing, all MyriCOM nodes transmit multicast frames
diff -urN linux-2.4.19-pre2/drivers/net/natsemi.c linux-2.4.19-pre3/drivers/net/natsemi.c
--- linux-2.4.19-pre2/drivers/net/natsemi.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/natsemi.c	Mon Mar 11 14:13:28 2002
@@ -105,6 +105,9 @@
 	version 1.0.14:
 		* Cleanup some messages and autoneg in ethtool (Tim Hockin)
 
+	version 1.0.13:
+		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
+
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
@@ -1731,36 +1734,15 @@
 	return &np->stats;
 }
 
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
-   them.  Select the endian-ness that results in minimal calculations.
-*/
-#if 0
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-#else
+/**
+ * dp83815_crc - computer CRC for hash table entries
+ *
+ * Note - this is, for some reason, *not* the same function
+ * as ether_crc_le() or ether_crc(), though it uses the
+ * same big-endian polynomial.
+ */
 #define DP_POLYNOMIAL			0x04C11DB7
-/* dp83815_crc - computer CRC for hash table entries */
-static unsigned ether_crc_le(int length, unsigned char *data)
+static unsigned dp83815_crc(int length, unsigned char *data)
 {
     u32 crc;
     u8 cur_byte;
@@ -1784,7 +1766,7 @@
 
     return (crc);
 }
-#endif
+
 
 void set_bit_le(int offset, unsigned char * data)
 {
@@ -1814,7 +1796,7 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+			set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
 					mc_filter);
 		}
 		rx_mode = RxFilterEnable | AcceptBroadcast 
diff -urN linux-2.4.19-pre2/drivers/net/pci-skeleton.c linux-2.4.19-pre3/drivers/net/pci-skeleton.c
--- linux-2.4.19-pre2/drivers/net/pci-skeleton.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/net/pci-skeleton.c	Mon Mar 11 14:13:28 2002
@@ -96,6 +96,7 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 
 #define NETDRV_VERSION		"1.0.0"
@@ -509,7 +510,6 @@
 static int netdrv_close (struct net_device *dev);
 static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
 static void netdrv_set_rx_mode (struct net_device *dev);
 static void netdrv_hw_start (struct net_device *dev);
 
@@ -1853,27 +1853,6 @@
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	DPRINTK ("ENTER\n");
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	DPRINTK ("EXIT\n");
-	return crc;
-}
-
-
 static void netdrv_set_rx_mode (struct net_device *dev)
 {
 	struct netdrv_private *tp = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.19-pre3/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.19-pre2/drivers/net/pcmcia/fmvj18x_cs.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/pcmcia/fmvj18x_cs.c	Mon Mar 11 14:13:28 2002
@@ -53,6 +53,7 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/crc32.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1248,27 +1249,6 @@
   Set the multicast/promiscuous mode for this adaptor.
 */
 
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-    unsigned int crc = 0xffffffff;	/* Initial value. */
-    while(--length >= 0) {
-	unsigned char current_octet = *data++;
-	int bit;
-	for (bit = 8; --bit >= 0; current_octet >>= 1) {
-	    if ((crc ^ current_octet) & 1) {
-		crc >>= 1;
-		crc ^= ethernet_polynomial_le;
-	    } else
-		crc >>= 1;
-	}
-    }
-    return crc;
-}
-
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
diff -urN linux-2.4.19-pre2/drivers/net/pcmcia/ray_cs.c linux-2.4.19-pre3/drivers/net/pcmcia/ray_cs.c
--- linux-2.4.19-pre2/drivers/net/pcmcia/ray_cs.c	Fri Oct 12 14:21:18 2001
+++ linux-2.4.19-pre3/drivers/net/pcmcia/ray_cs.c	Mon Mar 11 14:13:28 2002
@@ -999,7 +999,9 @@
 /*===========================================================================*/
 int ray_dev_init(struct net_device *dev)
 {
+#ifdef RAY_IMMEDIATE_INIT
     int i;
+#endif	/* RAY_IMMEDIATE_INIT */
     ray_dev_t *local = dev->priv;
     dev_link_t *link = local->finder;
 
@@ -1008,6 +1010,7 @@
         DEBUG(2,"ray_dev_init - device not present\n");
         return -1;
     }
+#ifdef RAY_IMMEDIATE_INIT
     /* Download startup parameters */
     if ( (i = dl_startup_params(dev)) < 0)
     {
@@ -1015,7 +1018,14 @@
            "returns 0x%x\n",i);
         return -1;
     }
-    
+#else	/* RAY_IMMEDIATE_INIT */
+    /* Postpone the card init so that we can still configure the card,
+     * for example using the Wireless Extensions. The init will happen
+     * in ray_open() - Jean II */
+    DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
+	  local->card_status);
+#endif	/* RAY_IMMEDIATE_INIT */
+
     /* copy mac and broadcast addresses to linux device */
     memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
     memset(dev->broadcast, 0xff, ETH_ALEN);
@@ -1245,6 +1255,22 @@
       wrq->u.freq.e = 0;
       break;
 
+      /* Set frequency/channel */
+    case SIOCSIWFREQ:
+      /* Reject if card is already initialised */
+      if(local->card_status != CARD_AWAITING_PARAM)
+	{
+	  err = -EBUSY;
+	  break;
+	}
+
+      /* Setting by channel number */
+      if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0))
+	err = -EOPNOTSUPP;
+      else
+	  local->sparm.b5.a_hop_pattern = wrq->u.freq.m;
+      break;
+
       /* Get current network name (ESSID) */
     case SIOCGIWESSID:
       if (wrq->u.data.pointer)
@@ -1262,6 +1288,46 @@
 	}
       break;
 
+      /* Set desired network name (ESSID) */
+    case SIOCSIWESSID:
+      /* Reject if card is already initialised */
+      if(local->card_status != CARD_AWAITING_PARAM)
+	{
+	  err = -EBUSY;
+	  break;
+	}
+
+	if (wrq->u.data.pointer)
+	{
+	    char	card_essid[IW_ESSID_MAX_SIZE + 1];
+	    
+	    /* Check if we asked for `any' */
+	    if(wrq->u.data.flags == 0)
+	    {
+		/* Corey : can you do that ? */
+		err = -EOPNOTSUPP;
+	    }
+	    else
+	    {
+		/* Check the size of the string */
+		if(wrq->u.data.length >
+		   IW_ESSID_MAX_SIZE + 1)
+		{
+		    err = -E2BIG;
+		    break;
+		}
+		copy_from_user(card_essid,
+			       wrq->u.data.pointer,
+			       wrq->u.data.length);
+		card_essid[IW_ESSID_MAX_SIZE] = '\0';
+
+		/* Set the ESSID in the card */
+		memcpy(local->sparm.b5.a_current_ess_id, card_essid,
+		       IW_ESSID_MAX_SIZE);
+	    }
+	}
+	break;
+
       /* Get current Access Point (BSSID in our case) */
     case SIOCGIWAP:
       memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN);
@@ -1304,6 +1370,34 @@
       wrq->u.rts.fixed = 1;
       break;
 
+      /* Set the desired RTS threshold */
+    case SIOCSIWRTS:
+    {
+	int rthr = wrq->u.rts.value;
+
+      /* Reject if card is already initialised */
+      if(local->card_status != CARD_AWAITING_PARAM)
+	{
+	  err = -EBUSY;
+	  break;
+	}
+
+	/* if(wrq->u.rts.fixed == 0) we should complain */
+#if WIRELESS_EXT > 8
+	if(wrq->u.rts.disabled)
+	    rthr = 32767;
+	else
+#endif /* WIRELESS_EXT > 8 */
+	    if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
+	    {
+		err = -EINVAL;
+		break;
+	    }
+	local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
+	local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
+    }
+    break;
+
       /* Get the current fragmentation threshold */
     case SIOCGIWFRAG:
       wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
@@ -1313,6 +1407,35 @@
 #endif /* WIRELESS_EXT > 8 */
       wrq->u.frag.fixed = 1;
       break;
+
+      /* Set the desired fragmentation threshold */
+    case SIOCSIWFRAG:
+    {
+	int fthr = wrq->u.frag.value;
+
+      /* Reject if card is already initialised */
+      if(local->card_status != CARD_AWAITING_PARAM)
+	{
+	  err = -EBUSY;
+	  break;
+	}
+
+	/* if(wrq->u.frag.fixed == 0) should complain */
+#if WIRELESS_EXT > 8
+	if(wrq->u.frag.disabled)
+	    fthr = 32767;
+	else
+#endif /* WIRELESS_EXT > 8 */
+	    if((fthr < 256) || (fthr > 2347)) /* To check out ! */
+	    {
+		err = -EINVAL;
+		break;
+	    }
+	local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
+	local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
+    }
+    break;
+
 #endif	/* WIRELESS_EXT > 7 */
 #if WIRELESS_EXT > 8
 
@@ -1323,6 +1446,33 @@
       else
 	wrq->u.mode = IW_MODE_ADHOC;
       break;
+
+      /* Set the current mode of operation */
+    case SIOCSIWMODE:
+    {
+	char card_mode = 1;
+	
+      /* Reject if card is already initialised */
+      if(local->card_status != CARD_AWAITING_PARAM)
+	{
+	  err = -EBUSY;
+	  break;
+	}
+
+	switch (wrq->u.mode)
+	{
+	case IW_MODE_ADHOC:
+	    card_mode = 0;
+	    // Fall through
+	case IW_MODE_INFRA:
+	    local->sparm.b5.a_network_type = card_mode;
+	    break;
+	default:
+	    err = -EINVAL;
+	}
+    }
+    break;
+
 #endif /* WIRELESS_EXT > 8 */
 #if WIRELESS_EXT > 7
       /* ------------------ IWSPY SUPPORT ------------------ */
@@ -1549,6 +1699,21 @@
     if (link->open == 0) local->num_multi = 0;
     link->open++;
 
+    /* If the card is not started, time to start it ! - Jean II */
+    if(local->card_status == CARD_AWAITING_PARAM) {
+	int i;
+
+	DEBUG(1,"ray_open: doing init now !\n");
+
+	/* Download startup parameters */
+	if ( (i = dl_startup_params(dev)) < 0)
+	  {
+	    printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
+		   "returns 0x%x\n",i);
+	    return -1;
+	  }
+     }
+
     if (sniffer) netif_stop_queue(dev);
     else         netif_start_queue(dev);
 
@@ -1572,6 +1737,11 @@
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
 
+    /* In here, we should stop the hardware (stop card from beeing active)
+     * and set local->card_status to CARD_AWAITING_PARAM, so that while the
+     * card is closed we can chage its configuration.
+     * Probably also need a COR reset to get sane state - Jean II */
+
     MOD_DEC_USE_COUNT;
 
     return 0;
diff -urN linux-2.4.19-pre2/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.19-pre3/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.4.19-pre2/drivers/net/pcmcia/smc91c92_cs.c	Tue Nov 13 09:02:30 2001
+++ linux-2.4.19-pre3/drivers/net/pcmcia/smc91c92_cs.c	Mon Mar 11 14:13:28 2002
@@ -34,6 +34,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -1740,31 +1741,6 @@
     return &smc->stats;
 }
 
-/*======================================================================
-
-    Compute the AUTODIN polynomial "CRC32" for ethernet packets.
-
-======================================================================*/
-
-static const u_int ethernet_polynomial = 0x04c11db7U;
-
-static u_int ether_crc(int length, u_char *data)
-{
-    int crc = 0xffffffff;	/* Initial value. */
-    
-    while (--length >= 0) {
-	u_char current_octet = *data++;
-	int bit;
-	for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-	    crc = (crc << 1) ^
-		((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-	}
-    }
-    /* The hash index is the either the upper or lower bits of the CRC, so
-     * we return the entire CRC.
-     */
-    return crc;
-}
 
 /*======================================================================
   
diff -urN linux-2.4.19-pre2/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.4.19-pre3/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.4.19-pre2/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/net/pcmcia/xircom_tulip_cb.c	Mon Mar 11 14:13:28 2002
@@ -101,6 +101,7 @@
 #include <linux/init.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
@@ -1518,43 +1519,6 @@
 	return -EOPNOTSUPP;
 }
 
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
-	u32 crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
-
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
    new frame, not around filling tp->setup_frame.  This is non-deterministic
diff -urN linux-2.4.19-pre2/drivers/net/pcnet32.c linux-2.4.19-pre3/drivers/net/pcnet32.c
--- linux-2.4.19-pre2/drivers/net/pcnet32.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/pcnet32.c	Mon Mar 11 14:13:28 2002
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -223,8 +224,6 @@
 
 #define PCNET32_TOTAL_SIZE 0x20
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
     u32 base;
@@ -1441,8 +1440,8 @@
     volatile u16 *mcast_table = (u16 *)&ib->filter;
     struct dev_mc_list *dmi=dev->mc_list;
     char *addrs;
-    int i, j, bit, byte;
-    u32 crc, poly = CRC_POLYNOMIAL_LE;
+    int i;
+    u32 crc;
 	
     /* set all multicast bits */
     if (dev->flags & IFF_ALLMULTI){ 
@@ -1463,19 +1462,7 @@
 	if (!(*addrs & 1))
 	    continue;
 	
-	crc = 0xffffffff;
-	for (byte = 0; byte < 6; byte++)
-	    for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-		int test;
-		
-		test = ((bit ^ crc) & 0x01);
-		crc >>= 1;
-		
-		if (test) {
-		    crc = crc ^ poly;
-		}
-	    }
-	
+	crc = ether_crc_le(6, addrs);
 	crc = crc >> 26;
 	mcast_table [crc >> 4] |= 1 << (crc & 0xf);
     }
diff -urN linux-2.4.19-pre2/drivers/net/ppp_async.c linux-2.4.19-pre3/drivers/net/ppp_async.c
--- linux-2.4.19-pre2/drivers/net/ppp_async.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre3/drivers/net/ppp_async.c	Mon Mar 11 14:13:28 2002
@@ -17,7 +17,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000227==
+ * ==FILEVERSION 20020125==
  */
 
 #include <linux/module.h>
@@ -33,7 +33,7 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 
-#define PPP_VERSION	"2.4.1"
+#define PPP_VERSION	"2.4.2"
 
 #define OBUFSIZE	256
 
@@ -62,6 +62,8 @@
 	struct sk_buff	*rpkt;
 	int		lcp_fcs;
 
+	atomic_t	refcnt;
+	struct semaphore dead_sem;
 	struct ppp_channel chan;	/* interface to generic ppp layer */
 	unsigned char	obuf[OBUFSIZE];
 };
@@ -108,6 +110,35 @@
  */
 
 /*
+ * We have a potential race on dereferencing tty->disc_data,
+ * because the tty layer provides no locking at all - thus one
+ * cpu could be running ppp_asynctty_receive while another
+ * calls ppp_asynctty_close, which zeroes tty->disc_data and
+ * frees the memory that ppp_asynctty_receive is using.  The best
+ * way to fix this is to use a rwlock in the tty struct, but for now
+ * we use a single global rwlock for all ttys in ppp line discipline.
+ */
+static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+
+static struct asyncppp *ap_get(struct tty_struct *tty)
+{
+	struct asyncppp *ap;
+
+	read_lock(&disc_data_lock);
+	ap = tty->disc_data;
+	if (ap != NULL)
+		atomic_inc(&ap->refcnt);
+	read_unlock(&disc_data_lock);
+	return ap;
+}
+
+static void ap_put(struct asyncppp *ap)
+{
+	if (atomic_dec_and_test(&ap->refcnt))
+		up(&ap->dead_sem);
+}
+
+/*
  * Called when a tty is put into PPP line discipline.
  */
 static int
@@ -135,6 +166,9 @@
 	ap->olim = ap->obuf;
 	ap->lcp_fcs = -1;
 
+	atomic_set(&ap->refcnt, 1);
+	init_MUTEX_LOCKED(&ap->dead_sem);
+
 	ap->chan.private = ap;
 	ap->chan.ops = &async_ops;
 	ap->chan.mtu = PPP_MRU;
@@ -155,19 +189,34 @@
 
 /*
  * Called when the tty is put into another line discipline
- * or it hangs up.
- * We assume that while we are in this routine, the tty layer
- * won't call any of the other line discipline entries for the
- * same tty.
+ * or it hangs up.  We have to wait for any cpu currently
+ * executing in any of the other ppp_asynctty_* routines to
+ * finish before we can call ppp_unregister_channel and free
+ * the asyncppp struct.  This routine must be called from
+ * process context, not interrupt or softirq context.
  */
 static void
 ppp_asynctty_close(struct tty_struct *tty)
 {
-	struct asyncppp *ap = tty->disc_data;
+	struct asyncppp *ap;
 
+	write_lock(&disc_data_lock);
+	ap = tty->disc_data;
+	tty->disc_data = 0;
+	write_unlock(&disc_data_lock);
 	if (ap == 0)
 		return;
-	tty->disc_data = 0;
+
+	/*
+	 * We have now ensured that nobody can start using ap from now
+	 * on, but we have to wait for all existing users to finish.
+	 * Note that ppp_unregister_channel ensures that no calls to
+	 * our channel ops (i.e. ppp_async_send/ioctl) are in progress
+	 * by the time it returns.
+	 */
+	if (!atomic_dec_and_test(&ap->refcnt))
+		down(&ap->dead_sem);
+
 	ppp_unregister_channel(&ap->chan);
 	if (ap->rpkt != 0)
 		kfree_skb(ap->rpkt);
@@ -203,9 +252,11 @@
 ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
 		   unsigned int cmd, unsigned long arg)
 {
-	struct asyncppp *ap = tty->disc_data;
+	struct asyncppp *ap = ap_get(tty);
 	int err, val;
 
+	if (ap == 0)
+		return -ENXIO;
 	err = -EFAULT;
 	switch (cmd) {
 	case PPPIOCGCHAN:
@@ -251,6 +302,7 @@
 		err = -ENOIOCTLCMD;
 	}
 
+	ap_put(ap);
 	return err;
 }
 
@@ -271,13 +323,14 @@
 ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
 		  char *flags, int count)
 {
-	struct asyncppp *ap = tty->disc_data;
+	struct asyncppp *ap = ap_get(tty);
 
 	if (ap == 0)
 		return;
 	spin_lock_bh(&ap->recv_lock);
 	ppp_async_input(ap, buf, flags, count);
 	spin_unlock_bh(&ap->recv_lock);
+	ap_put(ap);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
 	    && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
@@ -286,13 +339,14 @@
 static void
 ppp_asynctty_wakeup(struct tty_struct *tty)
 {
-	struct asyncppp *ap = tty->disc_data;
+	struct asyncppp *ap = ap_get(tty);
 
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	if (ap == 0)
 		return;
 	if (ppp_async_push(ap))
 		ppp_output_wakeup(&ap->chan);
+	ap_put(ap);
 }
 
 
diff -urN linux-2.4.19-pre2/drivers/net/ppp_generic.c linux-2.4.19-pre3/drivers/net/ppp_generic.c
--- linux-2.4.19-pre2/drivers/net/ppp_generic.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/ppp_generic.c	Mon Mar 11 14:13:28 2002
@@ -1,7 +1,7 @@
 /*
  * Generic PPP layer for Linux.
  *
- * Copyright 1999-2000 Paul Mackerras.
+ * Copyright 1999-2002 Paul Mackerras.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000902==
+ * ==FILEVERSION 20020217==
  */
 
 #include <linux/config.h>
@@ -43,10 +43,12 @@
 #include <linux/tcp.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
+#include <linux/rwsem.h>
+#include <linux/stddef.h>
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
-#define PPP_VERSION	"2.4.1"
+#define PPP_VERSION	"2.4.2"
 
 /*
  * Network protocols we support.
@@ -75,11 +77,11 @@
 	wait_queue_head_t rwait;	/* for poll on reading /dev/ppp */
 	atomic_t	refcnt;		/* # refs (incl /dev/ppp attached) */
 	int		hdrlen;		/* space to leave for headers */
-	struct list_head list;		/* link in all_* list */
 	int		index;		/* interface unit / channel number */
+	int		dead;		/* unit/channel has been shut down */
 };
 
-#define PF_TO_X(pf, X)	((X *)((char *)(pf)-(unsigned long)(&((X *)0)->file)))
+#define PF_TO_X(pf, X)		((X *)((char *)(pf) - offsetof(X, file)))
 
 #define PF_TO_PPP(pf)		PF_TO_X(pf, struct ppp)
 #define PF_TO_CHANNEL(pf)	PF_TO_X(pf, struct channel)
@@ -93,26 +95,27 @@
  * It can have 0 or more ppp channels connected to it.
  */
 struct ppp {
-	struct ppp_file	file;		/* stuff for read/write/poll */
-	struct list_head channels;	/* list of attached channels */
-	int		n_channels;	/* how many channels are attached */
-	spinlock_t	rlock;		/* lock for receive side */
-	spinlock_t	wlock;		/* lock for transmit side */
-	int		mru;		/* max receive unit */
-	unsigned int	flags;		/* control bits */
-	unsigned int	xstate;		/* transmit state bits */
-	unsigned int	rstate;		/* receive state bits */
-	int		debug;		/* debug flags */
+	struct ppp_file	file;		/* stuff for read/write/poll 0 */
+	struct file	*owner;		/* file that owns this unit 48 */
+	struct list_head channels;	/* list of attached channels 4c */
+	int		n_channels;	/* how many channels are attached 54 */
+	spinlock_t	rlock;		/* lock for receive side 58 */
+	spinlock_t	wlock;		/* lock for transmit side 5c */
+	int		mru;		/* max receive unit 60 */
+	unsigned int	flags;		/* control bits 64 */
+	unsigned int	xstate;		/* transmit state bits 68 */
+	unsigned int	rstate;		/* receive state bits 6c */
+	int		debug;		/* debug flags 70 */
 	struct slcompress *vj;		/* state for VJ header compression */
-	enum NPmode	npmode[NUM_NP];	/* what to do with each net proto */
-	struct sk_buff	*xmit_pending;	/* a packet ready to go out */
-	struct compressor *xcomp;	/* transmit packet compressor */
-	void		*xc_state;	/* its internal state */
-	struct compressor *rcomp;	/* receive decompressor */
-	void		*rc_state;	/* its internal state */
-	unsigned long	last_xmit;	/* jiffies when last pkt sent */
-	unsigned long	last_recv;	/* jiffies when last pkt rcvd */
-	struct net_device *dev;		/* network interface device */
+	enum NPmode	npmode[NUM_NP];	/* what to do with each net proto 78 */
+	struct sk_buff	*xmit_pending;	/* a packet ready to go out 88 */
+	struct compressor *xcomp;	/* transmit packet compressor 8c */
+	void		*xc_state;	/* its internal state 90 */
+	struct compressor *rcomp;	/* receive decompressor 94 */
+	void		*rc_state;	/* its internal state 98 */
+	unsigned long	last_xmit;	/* jiffies when last pkt sent 9c */
+	unsigned long	last_recv;	/* jiffies when last pkt rcvd a0 */
+	struct net_device *dev;		/* network interface device a4 */
 #ifdef CONFIG_PPP_MULTILINK
 	int		nxchan;		/* next channel to send something on */
 	u32		nxseq;		/* next sequence number to send */
@@ -144,11 +147,13 @@
  */
 struct channel {
 	struct ppp_file	file;		/* stuff for read/write/poll */
+	struct list_head list;		/* link in all/new_channels list */
 	struct ppp_channel *chan;	/* public channel data structure */
+	struct rw_semaphore chan_sem;	/* protects `chan' during chan ioctl */
 	spinlock_t	downl;		/* protects `chan', file.xq dequeue */
 	struct ppp	*ppp;		/* ppp unit we're connected to */
 	struct list_head clist;		/* link in list of channels per unit */
-	rwlock_t	upl;		/* protects `ppp' and `ulist' */
+	rwlock_t	upl;		/* protects `ppp' */
 #ifdef CONFIG_PPP_MULTILINK
 	u8		avail;		/* flag used in multilink stuff */
 	u8		had_frag;	/* >= 1 fragments have been sent */
@@ -166,12 +171,35 @@
  */
 
 /*
- * all_ppp_sem protects the all_ppp_units.
- * It also ensures that finding a ppp unit in the all_ppp_units list
+ * A cardmap represents a mapping from unsigned integers to pointers,
+ * and provides a fast "find lowest unused number" operation.
+ * It uses a broad (32-way) tree with a bitmap at each level.
+ * It is designed to be space-efficient for small numbers of entries
+ * and time-efficient for large numbers of entries.
+ */
+#define CARDMAP_ORDER	5
+#define CARDMAP_WIDTH	(1U << CARDMAP_ORDER)
+#define CARDMAP_MASK	(CARDMAP_WIDTH - 1)
+
+struct cardmap {
+	int shift;
+	unsigned long inuse;
+	struct cardmap *parent;
+	void *ptr[CARDMAP_WIDTH];
+};
+static void *cardmap_get(struct cardmap *map, unsigned int nr);
+static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
+static unsigned int cardmap_find_first_free(struct cardmap *map);
+static void cardmap_destroy(struct cardmap **map);
+
+/*
+ * all_ppp_sem protects the all_ppp_units mapping.
+ * It also ensures that finding a ppp unit in the all_ppp_units map
  * and updating its file.refcnt field is atomic.
  */
 static DECLARE_MUTEX(all_ppp_sem);
-static LIST_HEAD(all_ppp_units);
+static struct cardmap *all_ppp_units;
+static atomic_t ppp_unit_count = ATOMIC_INIT(0);
 
 /*
  * all_channels_lock protects all_channels and last_channel_index,
@@ -180,7 +208,9 @@
  */
 static spinlock_t all_channels_lock = SPIN_LOCK_UNLOCKED;
 static LIST_HEAD(all_channels);
+static LIST_HEAD(new_channels);
 static int last_channel_index;
+static atomic_t channel_count = ATOMIC_INIT(0);
 
 /* Get the PPP protocol number from a skb */
 #define PPP_PROTO(skb)	(((skb)->data[0] << 8) + (skb)->data[1])
@@ -205,10 +235,6 @@
 #define seq_after(a, b)		((s32)((a) - (b)) > 0)
 
 /* Prototypes. */
-static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file,
-			     char *buf, size_t count);
-static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf,
-			      size_t count);
 static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
 				unsigned int cmd, unsigned long arg);
 static void ppp_xmit_process(struct ppp *ppp);
@@ -235,6 +261,7 @@
 static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
 static struct ppp *ppp_create_interface(int unit, int *retp);
 static void init_ppp_file(struct ppp_file *pf, int kind);
+static void ppp_shutdown_interface(struct ppp *ppp);
 static void ppp_destroy_interface(struct ppp *ppp);
 static struct ppp *ppp_find_unit(int unit);
 static struct channel *ppp_find_channel(int unit);
@@ -303,7 +330,6 @@
 #define ppp_unlock(ppp)		do { ppp_recv_unlock(ppp); \
 				     ppp_xmit_unlock(ppp); } while (0)
 
-
 /*
  * /dev/ppp device routines.
  * The /dev/ppp device is used by pppd to control the ppp unit.
@@ -323,11 +349,16 @@
 
 static int ppp_release(struct inode *inode, struct file *file)
 {
-	struct ppp_file *pf = (struct ppp_file *) file->private_data;
+	struct ppp_file *pf = file->private_data;
+	struct ppp *ppp;
 
-	lock_kernel();
 	if (pf != 0) {
 		file->private_data = 0;
+		if (pf->kind == INTERFACE) {
+			ppp = PF_TO_PPP(pf);
+			if (file == ppp->owner)
+				ppp_shutdown_interface(ppp);
+		}
 		if (atomic_dec_and_test(&pf->refcnt)) {
 			switch (pf->kind) {
 			case INTERFACE:
@@ -339,37 +370,27 @@
 			}
 		}
 	}
-	unlock_kernel();
 	return 0;
 }
 
 static ssize_t ppp_read(struct file *file, char *buf,
 			size_t count, loff_t *ppos)
 {
-	struct ppp_file *pf = (struct ppp_file *) file->private_data;
-
-	return ppp_file_read(pf, file, buf, count);
-}
-
-static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file,
-			     char *buf, size_t count)
-{
+	struct ppp_file *pf = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	struct sk_buff *skb = 0;
 
-	ret = -ENXIO;
 	if (pf == 0)
-		goto out;		/* not currently attached */
-
+		return -ENXIO;
 	add_wait_queue(&pf->rwait, &wait);
-	current->state = TASK_INTERRUPTIBLE;
 	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		skb = skb_dequeue(&pf->rq);
 		if (skb)
 			break;
 		ret = 0;
-		if (pf->kind == CHANNEL && PF_TO_CHANNEL(pf)->chan == 0)
+		if (pf->dead)
 			break;
 		ret = -EAGAIN;
 		if (file->f_flags & O_NONBLOCK)
@@ -379,7 +400,7 @@
 			break;
 		schedule();
 	}
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&pf->rwait, &wait);
 
 	if (skb == 0)
@@ -402,21 +423,12 @@
 static ssize_t ppp_write(struct file *file, const char *buf,
 			 size_t count, loff_t *ppos)
 {
-	struct ppp_file *pf = (struct ppp_file *) file->private_data;
-
-	return ppp_file_write(pf, buf, count);
-}
-
-static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf,
-			      size_t count)
-{
+	struct ppp_file *pf = file->private_data;
 	struct sk_buff *skb;
 	ssize_t ret;
 
-	ret = -ENXIO;
 	if (pf == 0)
-		goto out;
-
+		return -ENXIO;
 	ret = -ENOMEM;
 	skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL);
 	if (skb == 0)
@@ -448,7 +460,7 @@
 /* No kernel lock - fine */
 static unsigned int ppp_poll(struct file *file, poll_table *wait)
 {
-	struct ppp_file *pf = (struct ppp_file *) file->private_data;
+	struct ppp_file *pf = file->private_data;
 	unsigned int mask;
 
 	if (pf == 0)
@@ -457,28 +469,52 @@
 	mask = POLLOUT | POLLWRNORM;
 	if (skb_peek(&pf->rq) != 0)
 		mask |= POLLIN | POLLRDNORM;
-	if (pf->kind == CHANNEL) {
-		struct channel *pch = PF_TO_CHANNEL(pf);
-		if (pch->chan == 0)
-			mask |= POLLHUP;
-	}
+	if (pf->dead)
+		mask |= POLLHUP;
 	return mask;
 }
 
 static int ppp_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	struct ppp_file *pf = (struct ppp_file *) file->private_data;
+	struct ppp_file *pf = file->private_data;
 	struct ppp *ppp;
 	int err = -EFAULT, val, val2, i;
 	struct ppp_idle idle;
 	struct npioctl npi;
-	int unit;
+	int unit, cflags;
 	struct slcompress *vj;
 
 	if (pf == 0)
 		return ppp_unattached_ioctl(pf, file, cmd, arg);
 
+	if (cmd == PPPIOCDETACH) {
+		/*
+		 * We have to be careful here... if the file descriptor
+		 * has been dup'd, we could have another process in the
+		 * middle of a poll using the same file *, so we had
+		 * better not free the interface data structures -
+		 * instead we fail the ioctl.  Even in this case, we
+		 * shut down the interface if we are the owner of it.
+		 * Actually, we should get rid of PPPIOCDETACH, userland
+		 * (i.e. pppd) could achieve the same effect by closing
+		 * this fd and reopening /dev/ppp.
+		 */
+		err = -EINVAL;
+		if (pf->kind == INTERFACE) {
+			ppp = PF_TO_PPP(pf);
+			if (file == ppp->owner)
+				ppp_shutdown_interface(ppp);
+		}
+		if (atomic_read(&file->f_count) <= 2) {
+			ppp_release(inode, file);
+			err = 0;
+		} else
+			printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n",
+			       atomic_read(&file->f_count));
+		return err;
+	}
+
 	if (pf->kind == CHANNEL) {
 		struct channel *pch = PF_TO_CHANNEL(pf);
 		struct ppp_channel *chan;
@@ -494,20 +530,13 @@
 			err = ppp_disconnect_channel(pch);
 			break;
 
-		case PPPIOCDETACH:
-			file->private_data = 0;
-			if (atomic_dec_and_test(&pf->refcnt))
-				ppp_destroy_channel(pch);
-			err = 0;
-			break;
-
 		default:
-			spin_lock_bh(&pch->downl);
+			down_read(&pch->chan_sem);
 			chan = pch->chan;
 			err = -ENOTTY;
 			if (chan && chan->ops->ioctl)
 				err = chan->ops->ioctl(chan, cmd, arg);
-			spin_unlock_bh(&pch->downl);
+			up_read(&pch->chan_sem);
 		}
 		return err;
 	}
@@ -520,13 +549,6 @@
 
 	ppp = PF_TO_PPP(pf);
 	switch (cmd) {
-	case PPPIOCDETACH:
-		file->private_data = 0;
-		if (atomic_dec_and_test(&pf->refcnt))
-			ppp_destroy_interface(ppp);
-		err = 0;
-		break;
-
 	case PPPIOCSMRU:
 		if (get_user(val, (int *) arg))
 			break;
@@ -538,10 +560,11 @@
 		if (get_user(val, (int *) arg))
 			break;
 		ppp_lock(ppp);
-		if (ppp->flags & ~val & SC_CCP_OPEN)
-			ppp_ccp_closed(ppp);
+		cflags = ppp->flags & ~val;
 		ppp->flags = val & SC_FLAG_BITS;
 		ppp_unlock(ppp);
+		if (cflags & SC_CCP_OPEN)
+			ppp_ccp_closed(ppp);
 		err = 0;
 		break;
 
@@ -677,6 +700,7 @@
 	default:
 		err = -ENOTTY;
 	}
+
 	return err;
 }
 
@@ -696,6 +720,7 @@
 		if (ppp == 0)
 			break;
 		file->private_data = &ppp->file;
+		ppp->owner = file;
 		err = -EFAULT;
 		if (put_user(ppp->file.index, (int *) arg))
 			break;
@@ -707,30 +732,28 @@
 		if (get_user(unit, (int *) arg))
 			break;
 		down(&all_ppp_sem);
+		err = -ENXIO;
 		ppp = ppp_find_unit(unit);
-		if (ppp != 0)
+		if (ppp != 0) {
 			atomic_inc(&ppp->file.refcnt);
+			file->private_data = &ppp->file;
+			err = 0;
+		}
 		up(&all_ppp_sem);
-		err = -ENXIO;
-		if (ppp == 0)
-			break;
-		file->private_data = &ppp->file;
-		err = 0;
 		break;
 
 	case PPPIOCATTCHAN:
 		if (get_user(unit, (int *) arg))
 			break;
 		spin_lock_bh(&all_channels_lock);
+		err = -ENXIO;
 		chan = ppp_find_channel(unit);
-		if (chan != 0)
+		if (chan != 0) {
 			atomic_inc(&chan->file.refcnt);
+			file->private_data = &chan->file;
+			err = 0;
+		}
 		spin_unlock_bh(&all_channels_lock);
-		err = -ENXIO;
-		if (chan == 0)
-			break;
-		file->private_data = &chan->file;
-		err = 0;
 		break;
 
 	default:
@@ -907,15 +930,16 @@
 	struct sk_buff *skb;
 
 	ppp_xmit_lock(ppp);
-	ppp_push(ppp);
-	while (ppp->xmit_pending == 0
-	       && (skb = skb_dequeue(&ppp->file.xq)) != 0)
-		ppp_send_frame(ppp, skb);
-	/* If there's no work left to do, tell the core net
-	   code that we can accept some more. */
-	if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0
-	    && ppp->dev != 0)
-		netif_wake_queue(ppp->dev);
+	if (ppp->dev != 0) {
+		ppp_push(ppp);
+		while (ppp->xmit_pending == 0
+		       && (skb = skb_dequeue(&ppp->file.xq)) != 0)
+			ppp_send_frame(ppp, skb);
+		/* If there's no work left to do, tell the core net
+		   code that we can accept some more. */
+		if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0)
+			netif_wake_queue(ppp->dev);
+	}
 	ppp_xmit_unlock(ppp);
 }
 
@@ -1800,7 +1824,7 @@
 {
 	struct channel *pch;
 
-	pch = kmalloc(sizeof(struct channel), GFP_ATOMIC);
+	pch = kmalloc(sizeof(struct channel), GFP_KERNEL);
 	if (pch == 0)
 		return -ENOMEM;
 	memset(pch, 0, sizeof(struct channel));
@@ -1812,11 +1836,13 @@
 #ifdef CONFIG_PPP_MULTILINK
 	pch->lastseq = -1;
 #endif /* CONFIG_PPP_MULTILINK */
+	init_rwsem(&pch->chan_sem);
 	spin_lock_init(&pch->downl);
 	pch->upl = RW_LOCK_UNLOCKED;
 	spin_lock_bh(&all_channels_lock);
 	pch->file.index = ++last_channel_index;
-	list_add(&pch->file.list, &all_channels);
+	list_add(&pch->list, &new_channels);
+	atomic_inc(&channel_count);
 	spin_unlock_bh(&all_channels_lock);
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -1829,7 +1855,9 @@
 {
 	struct channel *pch = chan->ppp;
 
-	return pch->file.index;
+	if (pch != 0)
+		return pch->file.index;
+	return -1;
 }
 
 /*
@@ -1851,7 +1879,7 @@
 
 /*
  * Disconnect a channel from the generic layer.
- * This can be called from mainline or BH/softirq level.
+ * This must be called in process context.
  */
 void
 ppp_unregister_channel(struct ppp_channel *chan)
@@ -1866,14 +1894,17 @@
 	 * This ensures that we have returned from any calls into the
 	 * the channel's start_xmit or ioctl routine before we proceed.
 	 */
+	down_write(&pch->chan_sem);
 	spin_lock_bh(&pch->downl);
 	pch->chan = 0;
 	spin_unlock_bh(&pch->downl);
+	up_write(&pch->chan_sem);
 	ppp_disconnect_channel(pch);
-	wake_up_interruptible(&pch->file.rwait);
 	spin_lock_bh(&all_channels_lock);
-	list_del(&pch->file.list);
+	list_del(&pch->list);
 	spin_unlock_bh(&all_channels_lock);
+	pch->file.dead = 1;
+	wake_up_interruptible(&pch->file.rwait);
 	if (atomic_dec_and_test(&pch->file.refcnt))
 		ppp_destroy_channel(pch);
 	MOD_DEC_USE_COUNT;
@@ -1902,9 +1933,9 @@
 ppp_set_compress(struct ppp *ppp, unsigned long arg)
 {
 	int err;
-	struct compressor *cp;
+	struct compressor *cp, *ocomp;
 	struct ppp_option_data data;
-	void *state;
+	void *state, *ostate;
 	unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
 #ifdef CONFIG_KMOD
 	char modname[32];
@@ -1930,41 +1961,39 @@
 #endif /* CONFIG_KMOD */
 	if (cp == 0)
 		goto out;
+	/*
+	 * XXX race: the compressor module could get unloaded between
+	 * here and when we do the comp_alloc or decomp_alloc call below.
+	 */
 
 	err = -ENOBUFS;
 	if (data.transmit) {
-		ppp_xmit_lock(ppp);
-		ppp->xstate &= ~SC_COMP_RUN;
-		if (ppp->xc_state != 0) {
-			ppp->xcomp->comp_free(ppp->xc_state);
-			ppp->xc_state = 0;
-		}
-		ppp_xmit_unlock(ppp);
-
 		state = cp->comp_alloc(ccp_option, data.length);
 		if (state != 0) {
 			ppp_xmit_lock(ppp);
+			ppp->xstate &= ~SC_COMP_RUN;
+			ocomp = ppp->xcomp;
+			ostate = ppp->xc_state;
 			ppp->xcomp = cp;
 			ppp->xc_state = state;
 			ppp_xmit_unlock(ppp);
+			if (ostate != 0)
+				ocomp->comp_free(ostate);
 			err = 0;
 		}
 
 	} else {
-		ppp_recv_lock(ppp);
-		ppp->rstate &= ~SC_DECOMP_RUN;
-		if (ppp->rc_state != 0) {
-			ppp->rcomp->decomp_free(ppp->rc_state);
-			ppp->rc_state = 0;
-		}
-		ppp_recv_unlock(ppp);
-
 		state = cp->decomp_alloc(ccp_option, data.length);
 		if (state != 0) {
 			ppp_recv_lock(ppp);
+			ppp->rstate &= ~SC_DECOMP_RUN;
+			ocomp = ppp->rcomp;
+			ostate = ppp->rc_state;
 			ppp->rcomp = cp;
 			ppp->rc_state = state;
 			ppp_recv_unlock(ppp);
+			if (ostate != 0)
+				ocomp->decomp_free(ostate);
 			err = 0;
 		}
 	}
@@ -2062,19 +2091,25 @@
 static void
 ppp_ccp_closed(struct ppp *ppp)
 {
-	ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP);
+	void *xstate, *rstate;
+	struct compressor *xcomp, *rcomp;
 
-	ppp->xstate &= ~SC_COMP_RUN;
-	if (ppp->xc_state) {
-		ppp->xcomp->comp_free(ppp->xc_state);
-		ppp->xc_state = 0;
-	}
+	ppp_lock(ppp);
+	ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP);
+	ppp->xstate = 0;
+	xcomp = ppp->xcomp;
+	xstate = ppp->xc_state;
+	ppp->xc_state = 0;
+	ppp->rstate = 0;
+	rcomp = ppp->rcomp;
+	rstate = ppp->rc_state;
+	ppp->rc_state = 0;
+	ppp_unlock(ppp);
 
-	ppp->xstate &= ~SC_DECOMP_RUN;
-	if (ppp->rc_state) {
-		ppp->rcomp->decomp_free(ppp->rc_state);
-		ppp->rc_state = 0;
-	}
+	if (xstate)
+		xcomp->comp_free(xstate);
+	if (rstate)
+		rcomp->decomp_free(rstate);
 }
 
 /* List of compressors. */
@@ -2194,39 +2229,27 @@
 ppp_create_interface(int unit, int *retp)
 {
 	struct ppp *ppp;
-	struct net_device *dev;
-	struct list_head *list;
-	int last_unit = -1;
-	int ret = -EEXIST;
+	struct net_device *dev = NULL;
+	int ret = -ENOMEM;
 	int i;
 
-	down(&all_ppp_sem);
-	list = &all_ppp_units;
-	while ((list = list->next) != &all_ppp_units) {
-		ppp = list_entry(list, struct ppp, file.list);
-		if ((unit < 0 && ppp->file.index > last_unit + 1)
-		    || (unit >= 0 && unit < ppp->file.index))
-			break;
-		if (unit == ppp->file.index)
-			goto out;	/* unit already exists */
-		last_unit = ppp->file.index;
-	}
-	if (unit < 0)
-		unit = last_unit + 1;
-
-	/* Create a new ppp structure and link it before `list'. */
-	ret = -ENOMEM;
 	ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL);
 	if (ppp == 0)
-		goto out;
-	memset(ppp, 0, sizeof(struct ppp));
+		goto err;
 	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	if (dev == 0) {
-		kfree(ppp);
-		goto out;
-	}
+	if (dev == 0)
+		goto err;
+	memset(ppp, 0, sizeof(struct ppp));
 	memset(dev, 0, sizeof(struct net_device));
 
+	ret = -EEXIST;
+	down(&all_ppp_sem);
+	if (unit < 0)
+		unit = cardmap_find_first_free(all_ppp_units);
+	else if (cardmap_get(all_ppp_units, unit) != NULL)
+		goto err_unlock;	/* unit already exists */
+
+	/* Initialize the new ppp unit */
 	ppp->file.index = unit;
 	ppp->mru = PPP_MRU;
 	init_ppp_file(&ppp->file, INTERFACE);
@@ -2251,19 +2274,26 @@
 	ret = register_netdevice(dev);
 	rtnl_unlock();
 	if (ret != 0) {
-		printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
-		kfree(dev);
-		kfree(ppp);
-		goto out;
+		printk(KERN_ERR "PPP: couldn't register device %s (%d)\n",
+		       dev->name, ret);
+		goto err_unlock;
 	}
 
-	list_add(&ppp->file.list, list->prev);
- out:
- 	up(&all_ppp_sem);
-	*retp = ret;
-	if (ret != 0)
-		ppp = 0;
+	atomic_inc(&ppp_unit_count);
+	cardmap_set(&all_ppp_units, unit, ppp);
+	up(&all_ppp_sem);
+	*retp = 0;
 	return ppp;
+
+ err_unlock:
+	up(&all_ppp_sem);
+ err:
+	*retp = ret;
+	if (ppp)
+		kfree(ppp);
+	if (dev)
+		kfree(dev);
+	return NULL;
 }
 
 /*
@@ -2280,19 +2310,48 @@
 }
 
 /*
- * Free up all the resources used by a ppp interface unit.
+ * Take down a ppp interface unit - called when the owning file
+ * (the one that created the unit) is closed or detached.
  */
-static void ppp_destroy_interface(struct ppp *ppp)
+static void ppp_shutdown_interface(struct ppp *ppp)
 {
 	struct net_device *dev;
-	int n_channels ;
 
 	down(&all_ppp_sem);
-	list_del(&ppp->file.list);
-
-	/* Last fd open to this ppp unit is being closed or detached:
-	   mark the interface down, free the ppp unit */
 	ppp_lock(ppp);
+	dev = ppp->dev;
+	ppp->dev = 0;
+	ppp_unlock(ppp);
+	if (dev) {
+		rtnl_lock();
+		dev_close(dev);
+		unregister_netdevice(dev);
+		rtnl_unlock();
+	}
+	cardmap_set(&all_ppp_units, ppp->file.index, NULL);
+	ppp->file.dead = 1;
+	ppp->owner = NULL;
+	wake_up_interruptible(&ppp->file.rwait);
+	up(&all_ppp_sem);
+}
+
+/*
+ * Free the memory used by a ppp unit.  This is only called once
+ * there are no channels connected to the unit and no file structs
+ * that reference the unit.
+ */
+static void ppp_destroy_interface(struct ppp *ppp)
+{
+	atomic_dec(&ppp_unit_count);
+
+	if (!ppp->file.dead || ppp->n_channels) {
+		/* "can't happen" */
+		printk(KERN_ERR "ppp: destroying ppp struct %p but dead=%d "
+		       "n_channels=%d !\n", ppp, ppp->file.dead,
+		       ppp->n_channels);
+		return;
+	}
+
 	ppp_ccp_closed(ppp);
 	if (ppp->vj) {
 		slhc_free(ppp->vj);
@@ -2313,52 +2372,27 @@
 		ppp->active_filter.filter = 0;
 	}
 #endif /* CONFIG_PPP_FILTER */
-	dev = ppp->dev;
-	ppp->dev = 0;
-	n_channels = ppp->n_channels ;
-	ppp_unlock(ppp);
 
-	if (dev) {
-		rtnl_lock();
-		dev_close(dev);
-		unregister_netdevice(dev);
-		rtnl_unlock();
-	}
-
-	/*
-	 * We can't acquire any new channels (since we have the
-	 * all_ppp_sem) so if n_channels is 0, we can free the
-	 * ppp structure.  Otherwise we leave it around until the
-	 * last channel disconnects from it.
-	 */
-	if (n_channels == 0) 
-		kfree(ppp);
-
-	up(&all_ppp_sem);
+	kfree(ppp);
 }
 
 /*
  * Locate an existing ppp unit.
- * The caller must have locked the all_ppp_sem.
+ * The caller should have locked the all_ppp_sem.
  */
 static struct ppp *
 ppp_find_unit(int unit)
 {
-	struct ppp *ppp;
-	struct list_head *list;
-
-	list = &all_ppp_units;
-	while ((list = list->next) != &all_ppp_units) {
-		ppp = list_entry(list, struct ppp, file.list);
-		if (ppp->file.index == unit)
-			return ppp;
-	}
-	return 0;
+	return cardmap_get(all_ppp_units, unit);
 }
 
 /*
  * Locate an existing ppp channel.
  * The caller should have locked the all_channels_lock.
+ * First we look in the new_channels list, then in the
+ * all_channels list.  If found in the new_channels list,
+ * we move it to the all_channels list.  This is for speed
+ * when we have a lot of channels in use.
  */
 static struct channel *
 ppp_find_channel(int unit)
@@ -2366,9 +2400,18 @@
 	struct channel *pch;
 	struct list_head *list;
 
+	list = &new_channels;
+	while ((list = list->next) != &new_channels) {
+		pch = list_entry(list, struct channel, list);
+		if (pch->file.index == unit) {
+			list_del(&pch->list);
+			list_add(&pch->list, &all_channels);
+			return pch;
+		}
+	}
 	list = &all_channels;
 	while ((list = list->next) != &all_channels) {
-		pch = list_entry(list, struct channel, file.list);
+		pch = list_entry(list, struct channel, list);
 		if (pch->file.index == unit)
 			return pch;
 	}
@@ -2392,12 +2435,9 @@
 	write_lock_bh(&pch->upl);
 	ret = -EINVAL;
 	if (pch->ppp != 0)
-		goto outwl;
-	ppp_lock(ppp);
-	spin_lock_bh(&pch->downl);
-	if (pch->chan == 0)		/* need to check this?? */
-		goto outr;
+		goto outl;
 
+	ppp_lock(ppp);
 	if (pch->file.hdrlen > ppp->file.hdrlen)
 		ppp->file.hdrlen = pch->file.hdrlen;
 	hdrlen = pch->file.hdrlen + 2;	/* for protocol bytes */
@@ -2406,15 +2446,14 @@
 	list_add_tail(&pch->clist, &ppp->channels);
 	++ppp->n_channels;
 	pch->ppp = ppp;
+	atomic_inc(&ppp->file.refcnt);
+	ppp_unlock(ppp);
 	ret = 0;
 
- outr:
-	spin_unlock_bh(&pch->downl);
-	ppp_unlock(ppp);
- outwl:
+ outl:
 	write_unlock_bh(&pch->upl);
  out:
- 	up(&all_ppp_sem);
+	up(&all_ppp_sem);
 	return ret;
 }
 
@@ -2426,25 +2465,21 @@
 {
 	struct ppp *ppp;
 	int err = -EINVAL;
-	int dead;
 
 	write_lock_bh(&pch->upl);
 	ppp = pch->ppp;
+	pch->ppp = NULL;
+	write_unlock_bh(&pch->upl);
 	if (ppp != 0) {
 		/* remove it from the ppp unit's list */
-		pch->ppp = NULL;
 		ppp_lock(ppp);
 		list_del(&pch->clist);
 		--ppp->n_channels;
-		dead = ppp->dev == 0 && ppp->n_channels == 0;
 		ppp_unlock(ppp);
-		if (dead)
-			/* Last disconnect from a ppp unit
-			   that is already dead: free it. */
-			kfree(ppp);
+		if (atomic_dec_and_test(&ppp->file.refcnt))
+			ppp_destroy_interface(ppp);
 		err = 0;
 	}
-	write_unlock_bh(&pch->upl);
 	return err;
 }
 
@@ -2453,6 +2488,14 @@
  */
 static void ppp_destroy_channel(struct channel *pch)
 {
+	atomic_dec(&channel_count);
+
+	if (!pch->file.dead) {
+		/* "can't happen" */
+		printk(KERN_ERR "ppp: destroying undead channel %p !\n",
+		       pch);
+		return;
+	}
 	skb_queue_purge(&pch->file.xq);
 	skb_queue_purge(&pch->file.rq);
 	kfree(pch);
@@ -2461,13 +2504,124 @@
 static void __exit ppp_cleanup(void)
 {
 	/* should never happen */
-	if (!list_empty(&all_ppp_units) || !list_empty(&all_channels))
+	if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
 		printk(KERN_ERR "PPP: removing module but units remain!\n");
+	cardmap_destroy(&all_ppp_units);
 	if (devfs_unregister_chrdev(PPP_MAJOR, "ppp") != 0)
 		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
 	devfs_unregister(devfs_handle);
 }
 
+/*
+ * Cardmap implementation.
+ */
+static void *cardmap_get(struct cardmap *map, unsigned int nr)
+{
+	struct cardmap *p;
+	int i;
+
+	for (p = map; p != NULL; ) {
+		if ((i = nr >> p->shift) >= CARDMAP_WIDTH)
+			return NULL;
+		if (p->shift == 0)
+			return p->ptr[i];
+		nr &= ~(CARDMAP_MASK << p->shift);
+		p = p->ptr[i];
+	}
+	return NULL;
+}
+
+static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
+{
+	struct cardmap *p;
+	int i;
+
+	p = *pmap;
+	if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
+		do {
+			/* need a new top level */
+			struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
+			memset(np, 0, sizeof(*np));
+			np->ptr[0] = p;
+			if (p != NULL) {
+				np->shift = p->shift + CARDMAP_ORDER;
+				p->parent = np;
+			} else
+				np->shift = 0;
+			p = np;
+		} while ((nr >> p->shift) >= CARDMAP_WIDTH);
+		*pmap = p;
+	}
+	while (p->shift > 0) {
+		i = (nr >> p->shift) & CARDMAP_MASK;
+		if (p->ptr[i] == NULL) {
+			struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
+			memset(np, 0, sizeof(*np));
+			np->shift = p->shift - CARDMAP_ORDER;
+			np->parent = p;
+			p->ptr[i] = np;
+		}
+		if (ptr == NULL)
+			clear_bit(i, &p->inuse);
+		p = p->ptr[i];
+	}
+	i = nr & CARDMAP_MASK;
+	p->ptr[i] = ptr;
+	if (ptr != NULL)
+		set_bit(i, &p->inuse);
+	else
+		clear_bit(i, &p->inuse);
+}
+
+static unsigned int cardmap_find_first_free(struct cardmap *map)
+{
+	struct cardmap *p;
+	unsigned int nr = 0;
+	int i;
+
+	if ((p = map) == NULL)
+		return 0;
+	for (;;) {
+		i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH);
+		if (i >= CARDMAP_WIDTH) {
+			if (p->parent == NULL)
+				return CARDMAP_WIDTH << p->shift;
+			p = p->parent;
+			i = (nr >> p->shift) & CARDMAP_MASK;
+			set_bit(i, &p->inuse);
+			continue;
+		}
+		nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift);
+		if (p->shift == 0 || p->ptr[i] == NULL)
+			return nr;
+		p = p->ptr[i];
+	}
+}
+
+static void cardmap_destroy(struct cardmap **pmap)
+{
+	struct cardmap *p, *np;
+	int i;
+
+	for (p = *pmap; p != NULL; p = np) {
+		if (p->shift != 0) {
+			for (i = 0; i < CARDMAP_WIDTH; ++i)
+				if (p->ptr[i] != NULL)
+					break;
+			if (i < CARDMAP_WIDTH) {
+				np = p->ptr[i];
+				p->ptr[i] = NULL;
+				continue;
+			}
+		}
+		np = p->parent;
+		kfree(p);
+	}
+	*pmap = NULL;
+}
+
+/* Module/initialization stuff */
+
 module_init(ppp_init);
 module_exit(ppp_cleanup);
 
diff -urN linux-2.4.19-pre2/drivers/net/ppp_synctty.c linux-2.4.19-pre3/drivers/net/ppp_synctty.c
--- linux-2.4.19-pre2/drivers/net/ppp_synctty.c	Thu Oct 11 11:17:22 2001
+++ linux-2.4.19-pre3/drivers/net/ppp_synctty.c	Mon Mar 11 14:13:28 2002
@@ -25,11 +25,11 @@
  * the generic PPP layer to give it frames to send and to process
  * received frames.  It implements the PPP line discipline.
  *
- * Part of the code in this driver was inspired by the old sync-only
+ * Part of the code in this driver was inspired by the old async-only
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000322==
+ * ==FILEVERSION 20020125==
  */
 
 #include <linux/module.h>
@@ -41,10 +41,12 @@
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
-#define PPP_VERSION	"2.4.1"
+#define PPP_VERSION	"2.4.2"
 
 /* Structure for storing local state. */
 struct syncppp {
@@ -65,6 +67,8 @@
 
 	struct sk_buff	*rpkt;
 
+	atomic_t	refcnt;
+	struct semaphore dead_sem;
 	struct ppp_channel chan;	/* interface to generic ppp layer */
 };
 
@@ -161,7 +165,36 @@
  */
 
 /*
- * Called when a tty is put into line discipline.
+ * We have a potential race on dereferencing tty->disc_data,
+ * because the tty layer provides no locking at all - thus one
+ * cpu could be running ppp_synctty_receive while another
+ * calls ppp_synctty_close, which zeroes tty->disc_data and
+ * frees the memory that ppp_synctty_receive is using.  The best
+ * way to fix this is to use a rwlock in the tty struct, but for now
+ * we use a single global rwlock for all ttys in ppp line discipline.
+ */
+static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+
+static struct syncppp *sp_get(struct tty_struct *tty)
+{
+	struct syncppp *ap;
+
+	read_lock(&disc_data_lock);
+	ap = tty->disc_data;
+	if (ap != NULL)
+		atomic_inc(&ap->refcnt);
+	read_unlock(&disc_data_lock);
+	return ap;
+}
+
+static void sp_put(struct syncppp *ap)
+{
+	if (atomic_dec_and_test(&ap->refcnt))
+		up(&ap->dead_sem);
+}
+
+/*
+ * Called when a tty is put into sync-PPP line discipline.
  */
 static int
 ppp_sync_open(struct tty_struct *tty)
@@ -185,6 +218,9 @@
 	ap->xaccm[3] = 0x60000000U;
 	ap->raccm = ~0U;
 
+	atomic_set(&ap->refcnt, 1);
+	init_MUTEX_LOCKED(&ap->dead_sem);
+
 	ap->chan.private = ap;
 	ap->chan.ops = &sync_ops;
 	ap->chan.mtu = PPP_MRU;
@@ -206,16 +242,34 @@
 
 /*
  * Called when the tty is put into another line discipline
- * (or it hangs up).
+ * or it hangs up.  We have to wait for any cpu currently
+ * executing in any of the other ppp_synctty_* routines to
+ * finish before we can call ppp_unregister_channel and free
+ * the syncppp struct.  This routine must be called from
+ * process context, not interrupt or softirq context.
  */
 static void
 ppp_sync_close(struct tty_struct *tty)
 {
-	struct syncppp *ap = tty->disc_data;
+	struct syncppp *ap;
 
+	write_lock(&disc_data_lock);
+	ap = tty->disc_data;
+	tty->disc_data = 0;
+	write_unlock(&disc_data_lock);
 	if (ap == 0)
 		return;
-	tty->disc_data = 0;
+
+	/*
+	 * We have now ensured that nobody can start using ap from now
+	 * on, but we have to wait for all existing users to finish.
+	 * Note that ppp_unregister_channel ensures that no calls to
+	 * our channel ops (i.e. ppp_sync_send/ioctl) are in progress
+	 * by the time it returns.
+	 */
+	if (!atomic_dec_and_test(&ap->refcnt))
+		down(&ap->dead_sem);
+
 	ppp_unregister_channel(&ap->chan);
 	if (ap->rpkt != 0)
 		kfree_skb(ap->rpkt);
@@ -251,9 +305,11 @@
 ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
 		  unsigned int cmd, unsigned long arg)
 {
-	struct syncppp *ap = tty->disc_data;
+	struct syncppp *ap = sp_get(tty);
 	int err, val;
 
+	if (ap == 0)
+		return -ENXIO;
 	err = -EFAULT;
 	switch (cmd) {
 	case PPPIOCGCHAN:
@@ -299,6 +355,7 @@
 		err = -ENOIOCTLCMD;
 	}
 
+	sp_put(ap);
 	return err;
 }
 
@@ -319,13 +376,14 @@
 ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
 		  char *flags, int count)
 {
-	struct syncppp *ap = tty->disc_data;
+	struct syncppp *ap = sp_get(tty);
 
 	if (ap == 0)
 		return;
 	spin_lock_bh(&ap->recv_lock);
 	ppp_sync_input(ap, buf, flags, count);
 	spin_unlock_bh(&ap->recv_lock);
+	sp_put(ap);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
 	    && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
@@ -334,13 +392,14 @@
 static void
 ppp_sync_wakeup(struct tty_struct *tty)
 {
-	struct syncppp *ap = tty->disc_data;
+	struct syncppp *ap = sp_get(tty);
 
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	if (ap == 0)
 		return;
 	if (ppp_sync_push(ap))
 		ppp_output_wakeup(&ap->chan);
+	sp_put(ap);
 }
 
 
diff -urN linux-2.4.19-pre2/drivers/net/pppoe.c linux-2.4.19-pre3/drivers/net/pppoe.c
--- linux-2.4.19-pre2/drivers/net/pppoe.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/pppoe.c	Mon Mar 11 14:13:28 2002
@@ -5,7 +5,7 @@
  * PPPoE --- PPP over Ethernet (RFC 2516)
  *
  *
- * Version:    0.6.9
+ * Version:    0.6.10
  *
  * 030700 :     Fixed connect logic to allow for disconnect.
  * 270700 :	Fixed potential SMP problems; we must protect against
@@ -31,6 +31,9 @@
  *		a memory leak.
  * 081001 :     Misc. cleanup (licence string, non-blocking, prevent
  *              reference of device on close).
+ * 121301 :     New ppp channels interface; cannot unregister a channel
+ *              from interrupts.  Thus, we mark the socket as a ZOMBIE
+ *              and do the unregistration later.
  *
  * Author:	Michal Ostrowski <mostrows@speakeasy.net>
  * Contributors:
@@ -273,10 +276,10 @@
 
 				lock_sock(sk);
 
-				if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+				if (sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){
 					pppox_unbind_sock(sk);
 					dev_put(dev);
-					sk->state = PPPOX_DEAD;
+					sk->state = PPPOX_ZOMBIE;
 					sk->state_change(sk);
 				}
 
@@ -439,8 +442,10 @@
 		 * one socket family type, we cannot (easily) distinguish
 		 * what kind of SKB it is during backlog rcv.
 		 */
-		if (sk->lock.users == 0)
+		if (sk->lock.users == 0) {
+			sk->state = PPPOX_ZOMBIE;
 			pppox_unbind_sock(sk);
+		}
 
 		bh_unlock_sock(sk);
 		sock_put(sk);
@@ -722,7 +727,7 @@
 		struct pppox_opt *relay_po;
 
 		err = -EBUSY;
-		if (sk->state & PPPOX_BOUND)
+		if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE|PPPOX_DEAD))
 			break;
 
 		err = -ENOTCONN;
diff -urN linux-2.4.19-pre2/drivers/net/sis900.c linux-2.4.19-pre3/drivers/net/sis900.c
--- linux-2.4.19-pre2/drivers/net/sis900.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/sis900.c	Mon Mar 11 14:13:28 2002
@@ -18,6 +18,7 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.03 Feb. 1 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem
    Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
    Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
@@ -60,6 +61,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -69,7 +71,7 @@
 #include "sis900.h"
 
 #define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.02 11/30/2001"
+#define SIS900_DRV_VERSION "v1.08.03 2/1/2002"
 
 static char version[] __devinitdata =
 KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -1981,26 +1983,7 @@
 static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision)
 {
 
-/* what is the correct value of the POLYNOMIAL ??
-   Donald Becker use 0x04C11DB7U
-   Joseph Zbiciak im14u2c@primenet.com gives me the
-   correct answer, thank you Joe !! */
-#define POLYNOMIAL 0x04C11DB7L
-	u32 crc = 0xffffffff, msb;
-	int  i, j;
-	u32  byte;
-
-	for (i = 0; i < 6; i++) {
-		byte = *addr++;
-		for (j = 0; j < 8; j++) {
-			msb = crc >> 31;
-			crc <<= 1;
-			if (msb ^ (byte & 1)) {
-				crc ^= POLYNOMIAL;
-			}
-			byte >>= 1;
-		}
-	}
+	u32 crc = ether_crc(6, addr);
 
 	/* leave 8 or 7 most siginifant bits */
 	if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
diff -urN linux-2.4.19-pre2/drivers/net/sk98lin/h/skdrv1st.h linux-2.4.19-pre3/drivers/net/sk98lin/h/skdrv1st.h
--- linux-2.4.19-pre2/drivers/net/sk98lin/h/skdrv1st.h	Sun Sep  9 10:45:43 2001
+++ linux-2.4.19-pre3/drivers/net/sk98lin/h/skdrv1st.h	Mon Mar 11 14:13:28 2002
@@ -116,6 +116,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 #include <asm/byteorder.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
diff -urN linux-2.4.19-pre2/drivers/net/sk98lin/skaddr.c linux-2.4.19-pre3/drivers/net/sk98lin/skaddr.c
--- linux-2.4.19-pre2/drivers/net/sk98lin/skaddr.c	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/drivers/net/sk98lin/skaddr.c	Mon Mar 11 14:13:28 2002
@@ -199,7 +199,6 @@
 /* defines ********************************************************************/
 
 
-#define CRC32_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
 #define HASH_BITS	6				/* #bits in hash */
 #define	SK_MC_BIT	0x01
 
@@ -534,18 +533,9 @@
 unsigned SkCrc32McHash(
 unsigned char *pMc)	/* Multicast address */
 {
-	unsigned Idx;
-	unsigned Bit;
-	unsigned Data;
-	unsigned Crc;
-
-	Crc = 0xFFFFFFFFUL;
-	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
-		Data = *pMc++;
-		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
-			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
-		}
-	}
+	u32 Crc;
+
+	Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
 
 	return (Crc & ((1 << HASH_BITS) - 1));
 }	/* SkCrc32McHash */
diff -urN linux-2.4.19-pre2/drivers/net/smc9194.c linux-2.4.19-pre3/drivers/net/smc9194.c
--- linux-2.4.19-pre2/drivers/net/smc9194.c	Tue Oct 16 21:56:29 2001
+++ linux-2.4.19-pre3/drivers/net/smc9194.c	Mon Mar 11 14:13:28 2002
@@ -51,6 +51,7 @@
  .				 allocation
  .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
  .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
+ .      11/08/01 Matt Domsch     Use common crc32 function
  ----------------------------------------------------------------------------*/
 
 static const char version[] =
@@ -69,6 +70,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/errno.h>
@@ -223,10 +225,6 @@
 */
 static void smc_set_multicast_list(struct net_device *dev);
 
-/*
- . CRC compute
- */
-static int crc32( char * s, int length );
 
 /*---------------------------------------------------------------
  .
@@ -436,7 +434,7 @@
 			continue;
 
 		/* only use the low order bits */
-		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+		position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
 
 		/* do some messy swapping to put the bit in the right spot */
 		multicast_table[invert3[position&7]] |=
@@ -452,33 +450,6 @@
 }
 
 /*
-  Finds the CRC32 of a set of bytes.
-  Again, from Peter Cammaert's code.
-*/
-static int crc32( char * s, int length ) {
-	/* indices */
-	int perByte;
-	int perBit;
-	/* crc polynomial for Ethernet */
-	const unsigned long poly = 0xedb88320;
-	/* crc value - preinitialized to all 1's */
-	unsigned long crc_value = 0xffffffff;
-
-	for ( perByte = 0; perByte < length; perByte ++ ) {
-		unsigned char	c;
-
-		c = *(s++);
-		for ( perBit = 0; perBit < 8; perBit++ ) {
-			crc_value = (crc_value>>1)^
-				(((crc_value^c)&0x01)?poly:0);
-			c >>= 1;
-		}
-	}
-	return	crc_value;
-}
-
-
-/*
  . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
  . Purpose:
  .    Attempt to allocate memory for a packet, if chip-memory is not
diff -urN linux-2.4.19-pre2/drivers/net/starfire.c linux-2.4.19-pre3/drivers/net/starfire.c
--- linux-2.4.19-pre2/drivers/net/starfire.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/starfire.c	Mon Mar 11 14:13:28 2002
@@ -112,6 +112,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1615,32 +1616,9 @@
 }
 
 
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
+/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
    them.  Select the endian-ness that results in minimal calculations.
 */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.4.19-pre2/drivers/net/sunbmac.c linux-2.4.19-pre3/drivers/net/sunbmac.c
--- linux-2.4.19-pre2/drivers/net/sunbmac.c	Tue Oct 30 15:08:11 2001
+++ linux-2.4.19-pre3/drivers/net/sunbmac.c	Mon Mar 11 14:13:28 2002
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -979,9 +980,6 @@
 	return &bp->enet_stats;
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void bigmac_set_multicast(struct net_device *dev)
 {
 	struct bigmac *bp = (struct bigmac *) dev->priv;
@@ -989,7 +987,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 tmp, crc, poly = CRC_POLYNOMIAL_LE;
+	u32 tmp, crc;
 
 	/* Disable the receiver.  The bit self-clears when
 	 * the operation is complete.
@@ -1022,17 +1020,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.4.19-pre2/drivers/net/sundance.c linux-2.4.19-pre3/drivers/net/sundance.c
--- linux-2.4.19-pre2/drivers/net/sundance.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/sundance.c	Mon Mar 11 14:13:28 2002
@@ -107,6 +107,7 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -1274,32 +1275,6 @@
 	return &np->stats;
 }
 
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
-   them.  Select the endian-ness that results in minimal calculations.
-*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
diff -urN linux-2.4.19-pre2/drivers/net/sungem.c linux-2.4.19-pre3/drivers/net/sungem.c
--- linux-2.4.19-pre2/drivers/net/sungem.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/sungem.c	Mon Mar 11 14:13:28 2002
@@ -37,6 +37,7 @@
 #include <linux/skbuff.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -1729,8 +1730,6 @@
 		       gp->regs + RXDMA_BLANK);
 }
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static u32
 gem_setup_multicast(struct gem *gp)
 {
@@ -1746,9 +1745,9 @@
 		rxcfg |= MAC_RXCFG_PROM;
 	} else {
 		u16 hash_table[16];
-		u32 crc, poly = CRC_POLYNOMIAL_LE;
+		u32 crc;
 		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i, j, bit, byte;
+		int i;
 
 		for (i = 0; i < 16; i++)
 			hash_table[i] = 0;
@@ -1761,17 +1760,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+ 			crc = ether_crc_le(6, addrs);
 			crc >>= 24;
 			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
 		}
diff -urN linux-2.4.19-pre2/drivers/net/sunhme.c linux-2.4.19-pre3/drivers/net/sunhme.c
--- linux-2.4.19-pre2/drivers/net/sunhme.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.19-pre3/drivers/net/sunhme.c	Mon Mar 11 14:13:28 2002
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1469,9 +1470,6 @@
 	add_timer(&hp->happy_timer);
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static int happy_meal_init(struct happy_meal *hp, int from_irq)
 {
 	unsigned long gregs        = hp->gregs;
@@ -1583,8 +1581,8 @@
 		u16 hash_table[4];
 		struct dev_mc_list *dmi = hp->dev->mc_list;
 		char *addrs;
-		int i, j, bit, byte;
-		u32 crc, poly = CRC_POLYNOMIAL_LE;
+		int i;
+		u32 crc;
 
 		for (i = 0; i < 4; i++)
 			hash_table[i] = 0;
@@ -1596,17 +1594,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
@@ -2385,8 +2373,8 @@
 	unsigned long bregs = hp->bigmacregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	int i;
+	u32 crc;
 
 	/* Lock out others. */
 	netif_stop_queue(dev);
@@ -2412,17 +2400,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.4.19-pre2/drivers/net/sunlance.c linux-2.4.19-pre3/drivers/net/sunlance.c
--- linux-2.4.19-pre2/drivers/net/sunlance.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/sunlance.c	Mon Mar 11 14:13:28 2002
@@ -62,12 +62,15 @@
  * 	          Anton Blanchard (anton@progsoc.uts.edu.au)
  * 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces.
  *		  David S. Miller (davem@redhat.com)
+ * 2.01:
+ *      11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
+ *		  
  */
 
 #undef DEBUG_DRIVER
 
 static char version[] =
-	"sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+	"sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
 
 static char lancestr[] = "LANCE";
 
@@ -86,6 +89,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -115,9 +119,6 @@
 #define LANCE_LOG_RX_BUFFERS 4
 #endif
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -1181,7 +1182,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 	
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -1211,19 +1212,7 @@
 		/* multicast address? */
 		if (!(*addrs & 1))
 			continue;
-
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++) {
-			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test)
-					crc = crc ^ poly;
-			}
-		}
+		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
 		if (lp->pio_buffer) {
 			u16 tmp = sbus_readw(&mcast_table[crc>>4]);
diff -urN linux-2.4.19-pre2/drivers/net/sunqe.c linux-2.4.19-pre3/drivers/net/sunqe.c
--- linux-2.4.19-pre2/drivers/net/sunqe.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre3/drivers/net/sunqe.c	Mon Mar 11 14:13:28 2002
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -622,9 +623,6 @@
 	return &qep->net_stats;
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void qe_set_multicast(struct net_device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -632,7 +630,7 @@
 	u8 new_mconfig = qep->mconfig;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	/* Lock out others. */
 	netif_stop_queue(dev);
@@ -660,18 +658,7 @@
 
 			if (!(*addrs & 1))
 				continue;
-
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.4.19-pre2/drivers/net/tc35815.c linux-2.4.19-pre3/drivers/net/tc35815.c
--- linux-2.4.19-pre2/drivers/net/tc35815.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/tc35815.c	Mon Mar 11 14:13:28 2002
@@ -7,6 +7,9 @@
  * Based on skelton.c by Donald Becker.
  * Copyright (C) 2000-2001 Toshiba Corporation
  *
+ * Cleaned up various non portable stuff (save_and_cli etc) and made it
+ * build on x86 platforms -- Alan Cox <alan@redhat.com> 20020302
+ *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
@@ -26,10 +29,13 @@
  * You should have received a copy of the  GNU General Public License along
  * with this program; if not, write  to the Free Software Foundation, Inc.,
  * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ *	Switch to spin_lock not lock_kernel for scalability.
  */
 
 static const char *version =
-	"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+	"tc35815.c:v0.00-ac 26/07/2000 by Toshiba Corporation\n";
 
 #include <linux/module.h>
 
@@ -41,7 +47,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -399,8 +405,14 @@
 };
 
 
+#if defined(__mips__)
+/* MIPS weirdness */
 extern unsigned long tc_readl(volatile __u32 *addr);
 extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#else
+#define tc_readl	readl
+#define tc_writel	writel
+#endif
 
 dma_addr_t priv_dma_handle;
 
@@ -465,7 +477,6 @@
 static void 	tc35815_chip_reset(struct net_device *dev);
 static void 	tc35815_chip_init(struct net_device *dev);
 static void 	tc35815_phy_chip_init(struct net_device *dev);
-static int 	tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 
 /* A list of all installed tc35815 devices. */
 static struct net_device *root_tc35815_dev = NULL;
@@ -496,7 +507,7 @@
 		return -ENODEV;
 
 	if (pdev) {
-		unsigned int pci_memaddr;
+		unsigned long pci_memaddr;
 		unsigned int pci_irq_line;
 
 		printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
@@ -560,12 +571,12 @@
 
 	/* Retrieve and print the ethernet address. */
 	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-		;
+		cpu_relax();
 	for (i = 0; i < 6; i += 2) {
 		unsigned short data;
 		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
 		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-			;
+			cpu_relax();
 		data = tc_readl(&tr->PROM_Data);
 		dev->dev_addr[i] = data & 0xff;
 		dev->dev_addr[i+1] = data >> 8;
@@ -831,6 +842,7 @@
 	panic("%s: Illegal queue state.", dev->name);
 }
 
+#if 0
 static void print_buf(char *add, int length)
 {
 	int i;
@@ -847,6 +859,7 @@
 	}
 	printk("\n");
 }
+#endif
 
 static void print_eth(char *add)
 {
@@ -907,7 +920,8 @@
 	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
 	int flags;
 
-	save_and_cli(flags);
+	save_flags(flags);
+	cli();
 	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
 	       dev->name, tc_readl(&tr->Tx_Stat));
 	/* Try to restart the adaptor. */
@@ -963,7 +977,8 @@
 		dma_cache_wback_inv((unsigned long)buf, length);
 #endif
 
-		save_and_cli(flags);
+		save_flags(flags);
+		cli();
 
 		/* failsafe... */
 		if (lp->tfd_start != lp->tfd_end)
@@ -1413,7 +1428,8 @@
 	unsigned long flags;
 
 	if (netif_running(dev)) {
-		save_and_cli(flags);
+		save_flags(flags);
+		cli();
 		/* Update the statistics from the device registers. */
 		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
 		restore_flags(flags);
@@ -1521,10 +1537,11 @@
 {
 	unsigned long data;
 	int flags;
-	save_and_cli(flags);
+	save_flags(flags);
+	cli();
 	tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-		;
+		cpu_relax();
 	data = tc_readl(&tr->MD_Data);
 	restore_flags(flags);
 	return data;
@@ -1533,11 +1550,12 @@
 static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
 {
 	int flags;
-	save_and_cli(flags);
+	save_flags(flags);
+	cli();
 	tc_writel(d, &tr->MD_Data);
 	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-		;
+		cpu_relax();
 	restore_flags(flags);
 }
 
@@ -1625,7 +1643,7 @@
 	/* reset the controller */
 	tc_writel(MAC_Reset, &tr->MAC_Ctl);
 	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
-		;
+		cpu_relax();
 
 	tc_writel(0, &tr->MAC_Ctl);
 
@@ -1662,7 +1680,8 @@
 	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
 	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-	save_and_cli(flags);
+	save_flags(flags);
+	cli();
 
 	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
 
@@ -1696,39 +1715,6 @@
 	restore_flags(flags);
 }
 
-static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
-{
-	int len = 0;
-	off_t pos = 0;
-	off_t begin = 0;
-	struct net_device *dev;
-
-	len += sprintf(buffer, "TC35815 statistics:\n");
-	for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
-		struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
-		len += sprintf(buffer + len,
-			       "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n",
-			       dev->name,
-			       lp->lstats.tx_ints,
-			       lp->lstats.rx_ints,
-			       lp->lstats.max_tx_qlen);
-		pos = begin + len;
-
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-    
-		if (pos > offset+length) break;
-	}
-
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
-  
-	if (len > length) len = length;
-  
-	return len;
-}
 
 /* XXX */
 void
diff -urN linux-2.4.19-pre2/drivers/net/tokenring/lanstreamer.c linux-2.4.19-pre3/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.19-pre2/drivers/net/tokenring/lanstreamer.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre3/drivers/net/tokenring/lanstreamer.c	Mon Mar 11 14:13:28 2002
@@ -60,6 +60,11 @@
  *		malloc free checks, reviewed code. <alan@redhat.com>
  *  03/13/00 - Added spinlocks for smp
  *  03/08/01 - Added support for module_init() and module_exit()
+ *  08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue
+ *             calls and other incorrectness - Kent Yoder <yoder1@us.ibm.com>
+ *  11/05/01 - Restructured the interrupt function, added delays, reduced the 
+ *             the number of TX descriptors to 1, which together can prevent 
+ *             the card from locking up the box - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -84,6 +89,14 @@
 
 #define STREAMER_NETWORK_MONITOR 0
 
+/* #define CONFIG_PROC_FS */
+
+/*
+ *  Allow or disallow ioctl's for debugging
+ */
+
+#define STREAMER_IOCTL 0
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -105,6 +118,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/version.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
@@ -121,7 +135,8 @@
  * Official releases will only have an a.b.c version number format.
  */
 
-static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
+                        "              v0.5.1 03/04/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -175,6 +190,10 @@
 MODULE_PARM(message_level,
 	    "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");
 
+#if STREAMER_IOCTL
+static int streamer_ioctl(struct net_device *, struct ifreq *, int);
+#endif
+
 static int streamer_reset(struct net_device *dev);
 static int streamer_open(struct net_device *dev);
 static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -206,6 +225,8 @@
   __u32 mmio_start, mmio_end, mmio_flags, mmio_len;
   int rc=0;
   static int card_no=-1;
+  u16 pcr;
+  u8 cls = 0;
 
 #if STREAMER_DEBUG
   printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);
@@ -281,7 +302,11 @@
 			dev->hard_start_xmit = &streamer_xmit;
 			dev->change_mtu = &streamer_change_mtu;
 			dev->stop = &streamer_close;
+#if STREAMER_IOCTL
+			dev->do_ioctl = &streamer_ioctl;
+#else
 			dev->do_ioctl = NULL;
+#endif
 			dev->set_multicast_list = &streamer_set_rx_mode;
 			dev->get_stats = &streamer_get_stats;
 			dev->set_mac_address = &streamer_set_mac_address;
@@ -303,6 +328,27 @@
 
   spin_lock_init(&streamer_priv->streamer_lock);
   
+  pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+  cls <<= 2;
+  if (cls != SMP_CACHE_BYTES) {
+         printk(KERN_INFO "  PCI cache line size set incorrectly "
+                "(%i bytes) by BIOS/FW, ", cls);
+         if (cls > SMP_CACHE_BYTES)
+                printk("expecting %i\n", SMP_CACHE_BYTES);
+         else {
+                printk("correcting to %i\n", SMP_CACHE_BYTES);
+                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+                                      SMP_CACHE_BYTES >> 2);
+         }
+  }
+
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
+  pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR);
+
+  pci_write_config_word (pdev, PCI_COMMAND, pcr);
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
   printk("%s \n", version);
   printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
 	 streamer_priv->streamer_card_name,
@@ -403,6 +449,7 @@
 	printk("GPR: %x\n", readw(streamer_mmio + GPR));
 	printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK));
 #endif
+	writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL );
 
 	if (streamer_priv->streamer_ring_speed == 0) {	/* Autosense */
 		writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE,
@@ -558,8 +605,6 @@
 	do {
 		int i;
 
-		save_flags(flags);
-		cli();
 		for (i = 0; i < SRB_COMMAND_SIZE; i += 2) {
 			writew(0, streamer_mmio + LAPDINC);
 		}
@@ -599,11 +644,12 @@
 		}
 		printk("\n");
 #endif
-
+		spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 		streamer_priv->srb_queued = 1;
 
 		/* signal solo that SRB command has been issued */
 		writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
+		spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
 
 		while (streamer_priv->srb_queued) {
 			interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ);
@@ -617,7 +663,6 @@
 				break;
 			}
 		}
-		restore_flags(flags);
 
 #if STREAMER_DEBUG
 		printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK));
@@ -767,9 +812,12 @@
 		streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
 		streamer_priv->streamer_tx_ring[i].buffer = 0;
 		streamer_priv->streamer_tx_ring[i].buflen = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd1 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
 	}
 	streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
-					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);;
+					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
 
 	streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
 	streamer_priv->tx_ring_free = 0;	/* next entry in tx ring to use */
@@ -941,37 +989,30 @@
 	__u8 *streamer_mmio = streamer_priv->streamer_mmio;
 	__u16 sisr;
 	__u16 misr;
-	__u16 sisrmask;
+	u8 max_intr = MAX_INTR;
 
-	sisrmask = SISR_MI;
-	writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
+	spin_lock(&streamer_priv->streamer_lock);
 	sisr = readw(streamer_mmio + SISR);
-	writew(~sisr, streamer_mmio + SISR_RUM);
-	misr = readw(streamer_mmio + MISR_RUM);
-	writew(~misr, streamer_mmio + MISR_RUM);
 
-	if (!sisr) 
-	{		/* Interrupt isn't for us */
-  	        writew(~misr,streamer_mmio+MISR_RUM);
-		return;
-	}
+	while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | 
+		       SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR))
+               && (max_intr > 0)) {
 
-	spin_lock(&streamer_priv->streamer_lock);
+		if(sisr & SISR_PAR_ERR) {
+			writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
 
-	if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
-	    || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
-		if (sisr & SISR_SRB_REPLY) {
-			if (streamer_priv->srb_queued == 1) {
-				wake_up_interruptible(&streamer_priv->srb_wait);
-			} else if (streamer_priv->srb_queued == 2) {
-				streamer_srb_bh(dev);
-			}
-			streamer_priv->srb_queued = 0;
+		else if(sisr & SISR_SERR_ERR) {
+			writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
-		/* SISR_SRB_REPLY */
+
+		else if(sisr & SISR_MI) {
+			misr = readw(streamer_mmio + MISR_RUM);
+
 		if (misr & MISR_TX2_EOF) {
-			while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) 
-			{
+				while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) {
 				streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1);
 				streamer_priv->free_tx_ring_entries++;
 				streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len;
@@ -981,6 +1022,9 @@
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0;
 			}
 			netif_wake_queue(dev);
 		}
@@ -989,7 +1033,30 @@
 			streamer_rx(dev);
 		}
 		/* MISR_RX_EOF */
-		if (sisr & SISR_ADAPTER_CHECK) {
+
+			if (misr & MISR_RX_NOBUF) {
+				/* According to the documentation, we don't have to do anything,  
+                                 * but trapping it keeps it out of /var/log/messages.  
+                                 */
+			}		/* SISR_RX_NOBUF */
+
+			writew(~misr, streamer_mmio + MISR_RUM);
+			(void)readw(streamer_mmio + MISR_RUM);
+		}
+
+		else if (sisr & SISR_SRB_REPLY) {
+			if (streamer_priv->srb_queued == 1) {
+				wake_up_interruptible(&streamer_priv->srb_wait);
+			} else if (streamer_priv->srb_queued == 2) {
+				streamer_srb_bh(dev);
+			}
+			streamer_priv->srb_queued = 0;
+
+			writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
+
+		else if (sisr & SISR_ADAPTER_CHECK) {
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
 			writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
 			printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
@@ -1001,38 +1068,37 @@
 		}
 
 		/* SISR_ADAPTER_CHECK */
-		if (sisr & SISR_ASB_FREE) {
+		else if (sisr & SISR_ASB_FREE) {
 			/* Wake up anything that is waiting for the asb response */
 			if (streamer_priv->asb_queued) {
 				streamer_asb_bh(dev);
 			}
+			writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ASB_FREE */
-		if (sisr & SISR_ARB_CMD) {
+		else if (sisr & SISR_ARB_CMD) {
 			streamer_arb_cmd(dev);
+			writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ARB_CMD */
-		if (sisr & SISR_TRB_REPLY) {
+		else if (sisr & SISR_TRB_REPLY) {
 			/* Wake up anything that is waiting for the trb response */
 			if (streamer_priv->trb_queued) {
 				wake_up_interruptible(&streamer_priv->
 						      trb_wait);
 			}
 			streamer_priv->trb_queued = 0;
+			writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_TRB_REPLY */
-		if (misr & MISR_RX_NOBUF) {
-			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
-			   /var/log/messages.  */
-		}		/* SISR_RX_NOBUF */
-	} else {
-		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",
-		       dev->name, sisr);
-		printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name,
-		       readw(streamer_mmio + SISR_MASK));
-	}			/* One if the interrupts we want */
 
-	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		sisr = readw(streamer_mmio + SISR);
+		max_intr--;
+	} /* while() */		
+
 	spin_unlock(&streamer_priv->streamer_lock) ; 
 }
 
@@ -1044,13 +1110,16 @@
 	unsigned long flags ;
 
 	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
-	netif_stop_queue(dev);
 
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
-		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len;
+
 		streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb;
 		streamer_priv->free_tx_ring_entries--;
 #if STREAMER_DEBUG_PACKETS
@@ -1067,12 +1136,13 @@
 #endif
 
 		writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+		(void)readl(streamer_mmio + TX2LFDA);
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
-		netif_wake_queue(dev);
 		spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 0;
 	} else {
+	        netif_stop_queue(dev);
 	        spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 1;
 	}
@@ -1092,12 +1162,13 @@
 	writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
 	writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 
 	streamer_priv->srb_queued = 1;
 	writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
 
+	spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
+
 	while (streamer_priv->srb_queued) 
 	{
 		interruptible_sleep_on_timeout(&streamer_priv->srb_wait,
@@ -1114,7 +1185,6 @@
 		}
 	}
 
-	restore_flags(flags);
 	streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
 
 	for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
@@ -1808,6 +1878,64 @@
 #endif
 #endif
 
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        int i;
+	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	u8 *streamer_mmio = streamer_priv->streamer_mmio;
+
+	switch(cmd) {
+	case IOCTL_SISR_MASK:
+		writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		break;
+	case IOCTL_SPIN_LOCK_TEST:
+	        printk(KERN_INFO "spin_lock() called.\n");
+		spin_lock(&streamer_priv->streamer_lock);
+		spin_unlock(&streamer_priv->streamer_lock);
+		printk(KERN_INFO "spin_unlock() finished.\n");
+		break;
+	case IOCTL_PRINT_BDAS:
+	        printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
+		       readw(streamer_mmio + RXBDA),
+		       readw(streamer_mmio + RXLBDA),
+		       readw(streamer_mmio + TX2FDA),
+		       readw(streamer_mmio + TX2LFDA));
+		break;
+	case IOCTL_PRINT_REGISTERS:
+	        printk(KERN_INFO "registers:\n");
+		printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask  %04x mask  %04x\n", 
+		       readw(streamer_mmio + SISR),
+		       readw(streamer_mmio + MISR_RUM),
+		       readw(streamer_mmio + LISR),
+		       readw(streamer_mmio + BCTL),
+		       readw(streamer_mmio + BMCTL_SUM),
+		       readw(streamer_mmio + SISR_MASK),
+		       readw(streamer_mmio + MISR_MASK));
+		break;
+	case IOCTL_PRINT_RX_BUFS:
+	        printk(KERN_INFO "Print rx bufs:\n");
+		for(i=0; i<STREAMER_RX_RING_SIZE; i++)
+		        printk(KERN_INFO "rx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_rx_ring[i].status);
+		break;
+	case IOCTL_PRINT_TX_BUFS:
+	        printk(KERN_INFO "Print tx bufs:\n");
+		for(i=0; i<STREAMER_TX_RING_SIZE; i++)
+		        printk(KERN_INFO "tx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_tx_ring[i].status);
+		break;
+	case IOCTL_RX_CMD:
+	        streamer_rx(dev);
+		printk(KERN_INFO "Sent rx command.\n");
+		break;
+	default:
+	        printk(KERN_INFO "Bad ioctl!\n");
+	}
+	return 0;
+}
+#endif
+
 static struct pci_driver streamer_pci_driver = {
   name:       "lanstreamer",
   id_table:   streamer_pci_tbl,
diff -urN linux-2.4.19-pre2/drivers/net/tokenring/lanstreamer.h linux-2.4.19-pre3/drivers/net/tokenring/lanstreamer.h
--- linux-2.4.19-pre2/drivers/net/tokenring/lanstreamer.h	Tue Mar 20 12:04:59 2001
+++ linux-2.4.19-pre3/drivers/net/tokenring/lanstreamer.h	Mon Mar 11 14:13:28 2002
@@ -56,11 +56,36 @@
  * 
  *  12/10/99 - Alpha Release 0.1.0
  *            First release to the public
+ *  08/15/01 - Added ioctl() definitions and others - Kent Yoder <yoder1@us.ibm.com>
  *
  */
 
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <asm/ioctl.h>
+#define IOCTL_PRINT_RX_BUFS   SIOCDEVPRIVATE
+#define IOCTL_PRINT_TX_BUFS   SIOCDEVPRIVATE+1
+#define IOCTL_RX_CMD          SIOCDEVPRIVATE+2
+#define IOCTL_TX_CMD          SIOCDEVPRIVATE+3
+#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
+#define IOCTL_PRINT_BDAS      SIOCDEVPRIVATE+5
+#define IOCTL_SPIN_LOCK_TEST  SIOCDEVPRIVATE+6
+#define IOCTL_SISR_MASK       SIOCDEVPRIVATE+7
+#endif
+
+/* MAX_INTR - the maximum number of times we can loop
+ * inside the interrupt function before returning
+ * control to the OS (maximum value is 256)
+ */
+#define MAX_INTR 5
+
+#define CLS 0x0C
+#define MLR 0x86
+#define LTR 0x0D
+
 #define BCTL 0x60
 #define BCTL_SOFTRESET (1<<15)
+#define BCTL_RX_FIFO_8 (1<<1)
+#define BCTL_TX_FIFO_8 (1<<3)
 
 #define GPR 0x4a
 #define GPR_AUTOSENSE (1<<2)
@@ -89,6 +114,7 @@
 #define SISR_MASK_RUM 0x58
 
 #define SISR_MI (1<<15)
+#define SISR_SERR_ERR (1<<14)
 #define SISR_TIMER (1<<11)
 #define SISR_LAP_PAR_ERR (1<<10)
 #define SISR_LAP_ACC_ERR (1<<9)
@@ -218,7 +244,13 @@
 /* Streamer defaults for buffers */
 
 #define STREAMER_RX_RING_SIZE 16	/* should be a power of 2 */
-#define STREAMER_TX_RING_SIZE 8	/* should be a power of 2 */
+/* Setting the number of TX descriptors to 1 is a workaround for an
+ * undocumented hardware problem with the lanstreamer board. Setting
+ * this to something higher may slightly increase the throughput you
+ * can get from the card, but at the risk of locking up the box. - 
+ * <yoder1@us.ibm.com>
+ */
+#define STREAMER_TX_RING_SIZE 1	/* should be a power of 2 */
 
 #define PKT_BUF_SZ 4096		/* Default packet size */
 
diff -urN linux-2.4.19-pre2/drivers/net/tulip/tulip_core.c linux-2.4.19-pre3/drivers/net/tulip/tulip_core.c
--- linux-2.4.19-pre2/drivers/net/tulip/tulip_core.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/net/tulip/tulip_core.c	Mon Mar 11 14:13:28 2002
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
@@ -1038,41 +1039,6 @@
    new frame, not around filling tp->setup_frame.  This is non-deterministic
    when re-entered but still correct. */
 
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
-	u32 crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
 #undef set_bit_le
 #define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
 
diff -urN linux-2.4.19-pre2/drivers/net/via-rhine.c linux-2.4.19-pre3/drivers/net/via-rhine.c
--- linux-2.4.19-pre2/drivers/net/via-rhine.c	Mon Feb 25 11:38:00 2002
+++ linux-2.4.19-pre3/drivers/net/via-rhine.c	Mon Mar 11 14:13:28 2002
@@ -161,6 +161,7 @@
 #include <linux/delay.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1535,26 +1536,6 @@
 	readw(ioaddr + RxMissed);
 }
 
-
-/* The big-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-    }
-    return crc;
-}
-
 static void via_rhine_set_rx_mode(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/net/wan/lmc/lmc_debug.c linux-2.4.19-pre3/drivers/net/wan/lmc/lmc_debug.c
--- linux-2.4.19-pre2/drivers/net/wan/lmc/lmc_debug.c	Fri Apr 21 16:08:45 2000
+++ linux-2.4.19-pre3/drivers/net/wan/lmc/lmc_debug.c	Mon Mar 11 14:13:28 2002
@@ -72,12 +72,12 @@
 
     if(in_interrupt()){
         printk("%s: * %s\n", dev->name, msg);
-//        while(jiffies < j+10)
+//        while(time_before(jiffies, j+10))
 //            ;
     }
     else {
         printk("%s: %s\n", dev->name, msg);
-        while(jiffies < j)
+        while(time_before(jiffies, j))
             schedule();
     }
 #endif
diff -urN linux-2.4.19-pre2/drivers/net/winbond-840.c linux-2.4.19-pre3/drivers/net/winbond-840.c
--- linux-2.4.19-pre2/drivers/net/winbond-840.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.19-pre3/drivers/net/winbond-840.c	Mon Mar 11 14:13:28 2002
@@ -138,6 +138,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/rtnetlink.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -388,7 +389,6 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void netdev_error(struct net_device *dev, int intr_status);
 static int  netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
 static u32 __set_rx_mode(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
@@ -1410,21 +1410,6 @@
 	return &np->stats;
 }
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-    }
-    return crc;
-}
 
 static u32 __set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.4.19-pre2/drivers/net/yellowfin.c linux-2.4.19-pre3/drivers/net/yellowfin.c
--- linux-2.4.19-pre2/drivers/net/yellowfin.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/net/yellowfin.c	Mon Mar 11 14:13:28 2002
@@ -125,6 +125,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/unaligned.h>
@@ -1339,29 +1340,6 @@
 
 /* Set or clear the multicast filter for this adaptor. */
 
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
-
 static void set_rx_mode(struct net_device *dev)
 {
 	struct yellowfin_private *yp = dev->priv;
diff -urN linux-2.4.19-pre2/drivers/pci/pci.c linux-2.4.19-pre3/drivers/pci/pci.c
--- linux-2.4.19-pre2/drivers/pci/pci.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/pci/pci.c	Mon Mar 11 14:13:28 2002
@@ -1996,11 +1996,13 @@
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
 EXPORT_SYMBOL(pci_proc_attach_bus);
 EXPORT_SYMBOL(pci_proc_detach_bus);
 #endif
+#endif
 
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
diff -urN linux-2.4.19-pre2/drivers/s390/misc/chandev.c linux-2.4.19-pre3/drivers/s390/misc/chandev.c
--- linux-2.4.19-pre2/drivers/s390/misc/chandev.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/s390/misc/chandev.c	Mon Mar 11 14:13:28 2002
@@ -902,25 +902,6 @@
 		       (int)lo_devno,(int)hi_devno);
 		return;
 	}
-	chandev_lock();
-	for_each(parms,chandev_parms_head)
-	{
-		if(chan_type&(parms->chan_type))
-		{
-			u16 lomax=MAX(parms->lo_devno,lo_devno),
-				himin=MIN(parms->hi_devno,lo_devno);
-			if(lomax<=himin)
-			{
-				chandev_unlock();
-				printk("chandev_add_parms detected overlapping "
-				       "parameter definitions for chan_type=0x%02x"
-				       " lo_devno=0x%04x  hi_devno=0x%04x\n,"
-				       " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno);
-				return;
-			}
-		}
-	}
-	chandev_unlock();
 	if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
 	{
 		parms->chan_type=chan_type;
@@ -1727,8 +1708,16 @@
 				   read->sch.devno>=curr_parms->lo_devno&&
 					read->sch.devno<=curr_parms->hi_devno)
 				{
-					probeinfo.parmstr=curr_parms->parmstr;
-					break;
+					if (!probeinfo.parmstr) {
+						probeinfo.parmstr = vmalloc(sizeof(curr_parms->parmstr)+1);
+						strcpy(probeinfo.parmstr, curr_parms->parmstr);
+					} else {
+						char *buf;
+
+						buf = vmalloc(strlen(probeinfo.parmstr)+strlen(curr_parms->parmstr)+2);
+						sprintf(buf, "%s,%s",probeinfo.parmstr, curr_parms->parmstr);
+						probeinfo.parmstr=buf;
+					}
 				}
 			}
 			if(force)
diff -urN linux-2.4.19-pre2/drivers/s390/net/Makefile linux-2.4.19-pre3/drivers/s390/net/Makefile
--- linux-2.4.19-pre2/drivers/s390/net/Makefile	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre3/drivers/s390/net/Makefile	Mon Mar 11 14:13:28 2002
@@ -9,8 +9,8 @@
 
 ctc-objs := ctcmain.o ctctty.o
 
-obj-y += iucv.o fsm.o
-obj-$(CONFIG_CTC) += ctc.o
+obj-$(CONFIG_IUCV) += iucv.o fsm.o
+obj-$(CONFIG_CTC) += ctc.o fsm.o
 obj-$(CONFIG_IUCV) += netiucv.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre2/drivers/s390/net/iucv.c linux-2.4.19-pre3/drivers/s390/net/iucv.c
--- linux-2.4.19-pre2/drivers/s390/net/iucv.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.19-pre3/drivers/s390/net/iucv.c	Mon Mar 11 14:13:29 2002
@@ -1,5 +1,5 @@
 /* 
- * $Id$
+ * $Id: iucv.c,v 1.32 2002/02/12 21:52:20 felfert Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision$
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.32 $
  *
  */
 
@@ -51,7 +51,7 @@
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
 
-#undef DEBUG
+#define DEBUG
 
 /* FLAGS:
  * All flags are defined in the field IPFLAGS1 of each function
@@ -165,6 +165,10 @@
  * declare_flag: is 0 when iucv_declare_buffer has not been called
  */
 static int declare_flag;
+/**
+ * register_flag: is 0 when external interrupt has not been registered
+ */
+static int register_flag;
 
 /****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
 /* Data struct 1: iparml_control
@@ -271,37 +275,56 @@
 
 static iucv_param * iucv_param_pool;
 
+MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
+MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE("GPL");
+#endif
+
 /*
  * Debugging stuff
  *******************************************************************************/
 
+
 #ifdef DEBUG
+static int debuglevel = 0;
+
+MODULE_PARM(debuglevel, "i");
+MODULE_PARM_DESC(debuglevel,
+ "Specifies the debug level (0=off ... 3=all)");
 
 static void
-iucv_dumpit(void *buf, int len)
+iucv_dumpit(char *title, void *buf, int len)
 {
 	int i;
 	__u8 *p = (__u8 *)buf;
 
-	printk(KERN_DEBUG "  ");
+	if (debuglevel < 3)
+		return;
+
+	printk(KERN_DEBUG __FUNCTION__ ": %s\n", title);
+	printk("  ");
 	for (i = 0; i < len; i++) {
 		if (!(i % 16) && i != 0)
 			printk ("\n  ");
 		else if (!(i % 4) && i != 0)
-			printk (" ");
-		printk ("%02X", *p++);
+			printk(" ");
+		printk("%02X", *p++);
 	}
 	if (len % 16)
 		printk ("\n");
 	return;
 }
-#define iucv_debug(fmt, args...) \
-printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args);
+#define iucv_debug(lvl, fmt, args...) \
+do { \
+	if (debuglevel >= lvl) \
+		printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args); \
+} while (0)
 
 #else
 
-#define iucv_debug(fmt, args...)
-#define iucv_dumpit(buf, len)
+#define iucv_debug(lvl, fmt, args...)
+#define iucv_dumpit(title, buf, len)
 
 #endif
 
@@ -310,6 +333,25 @@
  *******************************************************************************/
 
 /**
+ * print start banner
+ */
+static void
+iucv_banner(void)
+{
+	char vbuf[] = "$Revision: 1.32 $";
+	char *version = vbuf;
+
+	if ((version = strchr(version, ':'))) {
+		char *p = strchr(version + 1, '$');
+		if (p)
+			*p = '\0';
+	} else
+		version = " ??? ";
+	printk(KERN_INFO
+	       "IUCV lowlevel driver Version%s initialized\n", version);
+}
+
+/**
  * iucv_init - Initialization
  *
  * Allocates and initializes various data structures.
@@ -354,10 +396,26 @@
 	/* Initialize handler table */
 	INIT_LIST_HEAD(&iucv_handler_table);
 
+	iucv_banner();
 	return 0;
 }
 
 /**
+ * iucv_exit - De-Initialization
+ *
+ * Frees everything allocated from iucv_init.
+ */
+static void
+iucv_exit(void)
+{
+	if (iucv_external_int_buffer)
+		kfree(iucv_external_int_buffer);
+	if (iucv_param_pool)
+		kfree(iucv_param_pool);
+	printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
+}
+
+/**
  * grab_param: - Get a parameter buffer from the pre-allocated pool.
  *
  * This function searches for an unused element in the the pre-allocated pool
@@ -410,8 +468,8 @@
 {
 	ulong flags;
 
-	iucv_debug("entering");
-	iucv_dumpit(new, sizeof(handler));
+	iucv_debug(1, "entering");
+	iucv_dumpit("handler:", new, sizeof(handler));
 
 	spin_lock_irqsave (&iucv_lock, flags);
 	if (!list_empty(&iucv_handler_table)) {
@@ -424,7 +482,7 @@
 		list_for_each(lh, &iucv_handler_table) {
 			handler *h = list_entry(lh, handler, list);
 			if (memcmp(&new->id, &h->id, sizeof(h->id)) == 0) {
-				iucv_debug("ret 1");
+				iucv_debug(1, "ret 1");
 				spin_unlock_irqrestore (&iucv_lock, flags);
 				return 1;
 			}
@@ -437,35 +495,11 @@
 	list_add(&new->list, &iucv_handler_table);
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return 0;
 }
 
 /**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
-	unsigned long flags;
-
-	if ((!iucv_pathid_table) || (!handler))
-		return;
-
-	iucv_debug("entering");
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_del(&handler->list);
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	iucv_debug("exiting");
-	return;
-}
-
-/**
  * b2f0:
  * @code: identifier of IUCV call to CP.
  * @parm: pointer to 40 byte iparml area passed to CP
@@ -477,8 +511,7 @@
 static __inline__ ulong
 b2f0(__u32 code, void *parm)
 {
-	iucv_debug("iparml before b2f0 call:");
-	iucv_dumpit(parm, sizeof(iucv_param));
+	iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
 
 	asm volatile (
 		"LRA   1,0(%1)\n\t"
@@ -489,8 +522,7 @@
 		: "0", "1"
 		);
 
-	iucv_debug("iparml after b2f0 call:");
-	iucv_dumpit(parm, sizeof(iucv_param));
+	iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
 
 	return (unsigned long)*((__u8 *)(parm + 3));
 }
@@ -511,9 +543,9 @@
 {
 	ulong flags;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
-	iucv_debug("handler is pointing to %p", handler);
+	iucv_debug(1, "handler is pointing to %p", handler);
 
 	if (pathid > (max_connections - 1))
 		return -EINVAL;
@@ -521,7 +553,7 @@
 	spin_lock_irqsave (&iucv_lock, flags);
 	if (iucv_pathid_table[pathid]) {
 		spin_unlock_irqrestore (&iucv_lock, flags);
-		iucv_debug("pathid entry is %p", iucv_pathid_table[pathid]);
+		iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
 		printk(KERN_WARNING
 		       "%s: Pathid being used, error.\n", __FUNCTION__);
 		return -EINVAL;
@@ -529,7 +561,7 @@
 	iucv_pathid_table[pathid] = handler;
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return 0;
 }				/* end of add_pathid function */
 
@@ -546,24 +578,63 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 }
 
-/*
+/**
+ * iucv_declare_buffer_cpu0
+ * Register at VM for subsequent IUCV operations. This is always
+ * executed on CPU 0. Called from iucv_declare_buffer().
+ */
+static void
+iucv_declare_buffer_cpu0 (void *result)
+{
+	iparml_db *parm;
+
+	if (!(result && (smp_processor_id() == 0)))
+		return;
+	parm = (iparml_db *)grab_param();
+	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
+	if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
+		*((ulong *)result) = parm->iprcode;
+	release_param(parm);
+}
+
+/**
+ * iucv_retrieve_buffer_cpu0:
+ * Unregister IUCV usage at VM. This is always executed on CPU 0.
+ * Called from iucv_retrieve_buffer().
+ */
+void
+iucv_retrieve_buffer_cpu0 (void *result)
+{
+	iparml_control *parm;
+
+	if (smp_processor_id() != 0)
+		return;
+	parm = (iparml_control *)grab_param();
+	b2f0(RETRIEVE_BUFFER, parm);
+	release_param(parm);
+}
+
+/**
  * Name: iucv_declare_buffer
  * Purpose: Specifies the guests real address of an external
  *          interrupt.
  * Input: void
  * Output: iprcode - return code from b2f0 call
-*/
+ */
 int
 iucv_declare_buffer (void)
 {
-	ulong b2f0_result;
-	iparml_db *parm = (iparml_db *)grab_param();
+	ulong b2f0_result = 0x0deadbeef;
 
-	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
-	b2f0_result = b2f0(DECLARE_BUFFER, parm);
-	release_param(parm);
-	iucv_debug("Address of EIB = %p", iucv_external_int_buffer);
-	iucv_debug("exiting");
+	iucv_debug(1, "entering");
+	if (smp_processor_id() == 0)
+		iucv_declare_buffer_cpu0(&b2f0_result);
+	else
+		smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1);
+	iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
+	if (b2f0_result == 0x0deadbeef)
+	    b2f0_result = 0xaa;
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -576,20 +647,47 @@
 int
 iucv_retrieve_buffer (void)
 {
-	ulong b2f0_result = 0;
-	iparml_control *parm = (iparml_control *)grab_param();
+	iucv_debug(1, "entering");
+	if (declare_flag) {
+		if (smp_processor_id() == 0)
+			iucv_retrieve_buffer_cpu0(0);
+		else
+			smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1);
+		declare_flag = 0;
+	}
+	iucv_debug(1, "exiting");
+	return 0;
+}
 
-	iucv_debug("entering");
+/**
+ * iucv_remove_handler:
+ * @users_handler: handler to be removed
+ *
+ * Remove handler when application unregisters.
+ */
+static void
+iucv_remove_handler(handler *handler)
+{
+	unsigned long flags;
 
-	b2f0_result = b2f0(RETRIEVE_BUFFER, parm);
-	release_param(parm);
-	if (b2f0_result == 0) {
-		kfree(iucv_pathid_table);
-		iucv_pathid_table = NULL;
-		declare_flag = 0;
+	if ((!iucv_pathid_table) || (!handler))
+		return;
+
+	iucv_debug(1, "entering");
+
+	spin_lock_irqsave (&iucv_lock, flags);
+	list_del(&handler->list);
+	if (list_empty(&iucv_handler_table)) {
+		iucv_retrieve_buffer();
+		if (register_flag) {
+			unregister_external_interrupt(0x4000, iucv_irq_handler);
+			register_flag = 0;
+		}
 	}
-	iucv_debug("exiting");
-	return b2f0_result;
+	spin_unlock_irqrestore (&iucv_lock, flags);
+
+	iucv_debug(1, "exiting");
+	return;
 }
 
 /**
@@ -623,7 +721,7 @@
 	ulong rc = 0;		/* return code from function calls */
 	handler *new_handler;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	if (ops == NULL) {
 		/* interrupt table is not defined */
@@ -711,17 +809,41 @@
 	if (declare_flag == 0) {
 		rc = iucv_declare_buffer();
 		if (rc) {
+			char *err = "Unknown";
 			iucv_remove_handler(new_handler);
 			kfree(new_handler);
+			switch(rc) {
+				case 0x03:
+					err = "Directory error";
+					break;
+				case 0x0a:
+					err = "Invalid length";
+					break;
+				case 0x13:
+					err = "Buffer already exists";
+					break;
+				case 0x3e:
+					err = "Buffer overlap";
+					break;
+				case 0x5c:
+					err = "Paging or storage error";
+					break;
+				case 0xaa:
+					err = "Function not called";
+					break;
+			}
 			printk(KERN_WARNING "%s: iucv_declare_buffer "
-			       "returned %ld\n", __FUNCTION__, rc);
+			       "returned error 0x%02lx (%s)\n", __FUNCTION__, rc,
+			       err);
 			return NULL;
 		}
+		declare_flag = 1;
+	}
+	if (register_flag == 0) {
 		/* request the 0x4000 external interrupt */
 		rc = register_external_interrupt (0x4000, iucv_irq_handler);
 		if (rc) {
 			iucv_remove_handler(new_handler);
-			iucv_retrieve_buffer();
 			kfree (new_handler);
 			printk(KERN_WARNING "%s: "
 			       "register_external_interrupt returned %ld\n",
@@ -729,9 +851,10 @@
 			return NULL;
 
 		}
-		declare_flag = 1;
+		register_flag = 1;
 	}
-	iucv_debug("exiting");
+	MOD_INC_USE_COUNT;
+	iucv_debug(1, "exiting");
 	return new_handler;
 }				/* end of register function */
 
@@ -741,24 +864,45 @@
  *
  * Unregister application with IUCV.
  * Returns:
- *   Always 0
+ *   0 on success, -EINVAL, if specified handle is invalid.
  */
 
 int
 iucv_unregister_program (iucv_handle_t handle)
 {
-	handler *h = (handler *)handle;
+	handler *h = NULL;
+	struct list_head *lh;
 	int i;
 	ulong flags;
 
-	iucv_debug("entering");
-	iucv_debug("address of handler is %p", h);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "address of handler is %p", h);
+
+	/* Checking if handle is valid  */
+	spin_lock_irqsave (&iucv_lock, flags);
+	list_for_each(lh, &iucv_handler_table) {
+		if ((handler *)handle == list_entry(lh, handler, list)) {
+			h = (handler *)handle;
+			break;
+		}
+	}
+	if (!h) {
+		spin_unlock_irqrestore (&iucv_lock, flags);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
+		return -EINVAL;
+	}
 
 	/**
 	 * First, walk thru iucv_pathid_table and sever any pathid which is
 	 * still pointing to the handler to be removed.
 	 */
-	spin_lock_irqsave (&iucv_lock, flags);
 	for (i = 0; i < max_connections; i++)
 		if (iucv_pathid_table[i] == h) {
 			spin_unlock_irqrestore (&iucv_lock, flags);
@@ -770,7 +914,8 @@
 	iucv_remove_handler(h);
 	kfree(h);
 
-	iucv_debug("exiting");
+	MOD_DEC_USE_COUNT;
+	iucv_debug(1, "exiting");
 	return 0;
 }
 
@@ -811,8 +956,8 @@
 	handler *h = NULL;
 	iparml_control *parm;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	/* Checking if handle is valid  */
 	spin_lock_irqsave (&iucv_lock, flags);
@@ -825,9 +970,14 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
 	if (!h) {
-		printk(KERN_WARNING "%s: NULL handle passed by application "
-		       "or handler not found in iucv_handler_table\n",
-		       __FUNCTION__);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -849,7 +999,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -904,7 +1054,7 @@
 	handler *h = NULL;
 	__u8 no_memory[16] = "NO MEMORY";
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	/* Checking if handle is valid  */
 	spin_lock_irqsave (&iucv_lock, flags);
@@ -917,9 +1067,14 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
 	if (!h) {
-		printk(KERN_WARNING "%s: NULL handle passed by application "
-		       "or handler not found in iucv_handler_table\n",
-		       __FUNCTION__);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -971,7 +1126,7 @@
 		return(add_pathid_result);
 	}
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -993,8 +1148,8 @@
 	iparml_purge *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_purge *)grab_param();
 
@@ -1012,8 +1167,8 @@
 	
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -1099,8 +1254,8 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_control *)grab_param();
 
@@ -1110,8 +1265,8 @@
 	b2f0_result = b2f0(QUIESCE, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1152,7 +1307,7 @@
 	ulong b2f0_result;
 	int moved = 0;	/* number of bytes moved from parmlist to buffer */
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1170,9 +1325,9 @@
 
 	if (b2f0_result == 0 || b2f0_result == 5) {
 		if (flags1_out) {
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 		}
 
 		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
@@ -1199,7 +1354,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1242,7 +1397,7 @@
 	ulong b2f0_result;
 	int i = 0, moved = 0, need_to_move = 8, dyn_len;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1261,9 +1416,9 @@
 	if (b2f0_result == 0 || b2f0_result == 5) {
 
 		if (flags1_out) {
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 		}
 
 		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
@@ -1316,7 +1471,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1337,8 +1492,8 @@
 	iparml_db *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_db *)grab_param();
 
@@ -1350,8 +1505,8 @@
 	b2f0_result = b2f0(REJECT, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1391,7 +1546,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1415,7 +1570,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1457,7 +1612,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1482,7 +1637,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1511,7 +1666,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	parm = (iparml_dpl *)grab_param();
 
@@ -1524,7 +1679,7 @@
 	b2f0_result = b2f0(REPLY, parm);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1543,8 +1698,8 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_control *)grab_param();
 
@@ -1554,7 +1709,7 @@
 	b2f0_result = b2f0(RESUME, parm);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1582,7 +1737,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1603,7 +1758,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1637,7 +1792,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1657,7 +1812,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1686,7 +1841,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	parm = (iparml_dpl *)grab_param();
 
@@ -1703,7 +1858,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1741,7 +1896,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer || !ansbuf)
 		return -EINVAL;
@@ -1764,7 +1919,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1804,7 +1959,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer || !ansbuf)
 		return -EINVAL;
@@ -1825,7 +1980,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1861,7 +2016,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!ansbuf)
 		return -EINVAL;
@@ -1883,7 +2038,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1924,7 +2079,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!ansbuf)
 		return -EINVAL;
@@ -1944,7 +2099,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1967,7 +2122,7 @@
 	iparml_set_mask *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	parm = (iparml_set_mask *)grab_param();
 
@@ -1976,8 +2131,8 @@
 	b2f0_result = b2f0(SETMASK, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1996,7 +2151,7 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 	parm = (iparml_control *)grab_param();
 
 	memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
@@ -2008,7 +2163,7 @@
 		iucv_remove_pathid(pathid);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -2073,10 +2228,10 @@
 	int rc = 0, j = 0;
 	__u8 no_listener[16] = "NO LISTENER";
 
-	iucv_debug("entering, pathid %d, type %02X",
+	iucv_debug(2, "entering, pathid %d, type %02X",
 		 int_buf->ippathid, int_buf->iptype);
-	iucv_debug("External Interrupt Buffer:");
-	iucv_dumpit(int_buf, sizeof(iucv_GeneralInterrupt));
+	iucv_dumpit("External Interrupt Buffer:",
+		    int_buf, sizeof(iucv_GeneralInterrupt));
 
 	ASCEBC (no_listener, 16);
 
@@ -2088,9 +2243,7 @@
 		} else {
 			h = iucv_pathid_table[int_buf->ippathid];
 			interrupt = h->interrupt_table;
-
-			iucv_debug("Handler:");
-			iucv_dumpit(h, sizeof(handler));
+			iucv_dumpit("Handler:", h, sizeof(handler));
 		}
 	}
 
@@ -2107,14 +2260,15 @@
 					temp_buff2[j] &= (h->id.mask)[j];
 				}
 				
-				iucv_debug("temp_buff1:");
-				iucv_dumpit(temp_buff1, sizeof(temp_buff1));
-				iucv_debug("temp_buff2");
-				iucv_dumpit(temp_buff2, sizeof(temp_buff2));
+				iucv_dumpit("temp_buff1:",
+					    temp_buff1, sizeof(temp_buff1));
+				iucv_dumpit("temp_buff2",
+					    temp_buff2, sizeof(temp_buff2));
 				
 				if (memcmp (temp_buff1, temp_buff2, 24) == 0) {
 					
-					iucv_debug("found a matching handler");
+					iucv_debug(2,
+						   "found a matching handler");
 					break;
 				}
 			}
@@ -2125,7 +2279,8 @@
 				if (rc) {
 					iucv_sever (int_buf->ippathid,
 						    no_listener);
-					iucv_debug("add_pathid failed, rc = %d",
+					iucv_debug(1,
+						   "add_pathid failed, rc = %d",
 						   rc);
 				} else {
 					interrupt = h->interrupt_table;
@@ -2149,7 +2304,8 @@
 						(iucv_ConnectionComplete *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionComplete not called");
+					iucv_debug(1,
+						   "ConnectionComplete not called");
 			} else
 				iucv_sever(int_buf->ippathid, no_listener);
 			break;
@@ -2174,7 +2330,8 @@
 						(iucv_ConnectionQuiesced *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionQuiesced not called");
+					iucv_debug(1,
+						   "ConnectionQuiesced not called");
 			}
 			break;
 			
@@ -2185,7 +2342,8 @@
 						(iucv_ConnectionResumed *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionResumed not called");
+					iucv_debug(1,
+						   "ConnectionResumed not called");
 			}
 			break;
 			
@@ -2197,7 +2355,8 @@
 						(iucv_MessageComplete *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("MessageComplete not called");
+					iucv_debug(2,
+						   "MessageComplete not called");
 			}
 			break;
 			
@@ -2209,7 +2368,8 @@
 						(iucv_MessagePending *) int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("MessagePending not called");
+					iucv_debug(2,
+						   "MessagePending not called");
 			}
 			break;
 		default:		/* unknown iucv type */
@@ -2218,7 +2378,7 @@
 			break;
 	}			/* end switch */
 	
-	iucv_debug("exiting pathid %d, type %02X",
+	iucv_debug(2, "exiting pathid %d, type %02X",
 		 int_buf->ippathid, int_buf->iptype);
 
 	return;
@@ -2256,6 +2416,9 @@
 	return;
 }
 
+module_init(iucv_init);
+module_exit(iucv_exit);
+
 /**
  * Export all public stuff
  */
diff -urN linux-2.4.19-pre2/drivers/s390/net/netiucv.c linux-2.4.19-pre3/drivers/s390/net/netiucv.c
--- linux-2.4.19-pre2/drivers/s390/net/netiucv.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.19-pre3/drivers/s390/net/netiucv.c	Mon Mar 11 14:13:29 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.16 2001/12/03 14:28:45 felfert Exp $
+ * $Id: netiucv.c,v 1.17 2002/02/12 21:52:20 felfert Exp $
  *
  * IUCV network driver
  *
@@ -28,7 +28,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.16 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.17 $
  *
  */
 
@@ -70,7 +70,7 @@
 MODULE_PARM (iucv, "1s");
 MODULE_PARM_DESC (iucv,
 		  "Specify the initial remote userids for iucv0 .. iucvn:\n"
-		  "iucv=userid0:userid1:...:useridN\n");
+		  "iucv=userid0:userid1:...:useridN");
 #endif
 
 static char *iucv = "";
@@ -2005,7 +2005,7 @@
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.16 $";
+	char vbuf[] = "$Revision: 1.17 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff -urN linux-2.4.19-pre2/drivers/s390/s390io.c linux-2.4.19-pre3/drivers/s390/s390io.c
--- linux-2.4.19-pre2/drivers/s390/s390io.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre3/drivers/s390/s390io.c	Mon Mar 11 14:13:29 2002
@@ -93,7 +93,6 @@
 
 static spinlock_t  adapter_lock = SPIN_LOCK_UNLOCKED;
                                           // adapter interrupt lock
-static psw_t      io_sync_wait;           // wait PSW for sync IO, prot. by sync_isc
 static int        cons_dev          = -1; // identify console device
 static int        init_IRQ_complete = 0;
 static int        cio_show_msg      = 0;
@@ -1413,7 +1412,7 @@
 		 */
 		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
 		{
-			psw_t            io_new_psw;
+			unsigned long    psw_mask;
 			int              ccode;
 			uint64_t         time_start;    	
 			uint64_t         time_curr;    	
@@ -1431,30 +1430,25 @@
 			 *  sync. interrupt arrived we reset the I/O old PSW to
 			 *  its original value.
 			 */
-			memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
 
 			ccode = iac();
 
 			switch (ccode) {
 			case 0:  		// primary-space
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_PRIM_SPACE_MODE
-				                    | _PSW_IO_WAIT;
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
 				break;
 			case 1:			// secondary-space
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_SEC_SPACE_MODE
-				                    | _PSW_IO_WAIT;
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
 				break;
 			case 2:			// access-register
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_ACC_REG_MODE
-				                    | _PSW_IO_WAIT;
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
 				break;
 			case 3:			// home-space	
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_HOME_SPACE_MODE
-				                    | _PSW_IO_WAIT;
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
 				break;
 			default:
 				panic( "start_IO() : unexpected "
@@ -1463,8 +1457,6 @@
 				break;
 			} /* endswitch */
 
-			io_sync_wait.addr = FIX_PSW(&&io_wakeup);
-
 			/*
 			 * Martin didn't like modifying the new PSW, now we take
 			 *  a fast exit in do_IRQ() instead
@@ -1502,9 +1494,8 @@
 				}
 				else
 				{
-					__load_psw( io_sync_wait );
+					__load_psw_mask( psw_mask );
 
-io_wakeup:
 					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
 
 				} /* endif */
@@ -1984,7 +1975,7 @@
 			{
 				int              io_sub;
 				__u32            io_parm;
-				psw_t            io_new_psw;
+				unsigned long    psw_mask;
 				int              ccode;
   	
 				int              ready = 0;
@@ -1999,32 +1990,29 @@
 				 *  arrived we reset the I/O old PSW to its
 				 *  original value.
 				 */
-				memcpy( &io_new_psw,
-				        &lc->io_new_psw,
-				        sizeof(psw_t));
 
 				ccode = iac();
 
 				switch (ccode) {
 				case 0:  		// primary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_PRIM_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_PRIM_SPACE_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 1:			// secondary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_SEC_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_SEC_SPACE_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 2:			// access-register
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_ACC_REG_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_ACC_REG_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 3:			// home-space	
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_HOME_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_HOME_SPACE_MODE
+						| _PSW_IO_WAIT;
 					break;
 				default:
 					panic( "halt_IO() : unexpected "
@@ -2033,8 +2021,6 @@
 					break;
 				} /* endswitch */
 
-				io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
-
 				/*
 				 * Martin didn't like modifying the new PSW, now we take
 				 *  a fast exit in do_IRQ() instead
@@ -2044,8 +2030,8 @@
 				do
 				{
 
-					__load_psw( io_sync_wait );
-hio_wakeup:
+					__load_psw_mask( psw_mask );
+
 				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
 				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
 
@@ -2243,7 +2229,7 @@
 			{
 				int              io_sub;
 				__u32            io_parm;
-				psw_t            io_new_psw;
+				unsigned long    psw_mask;
 				int              ccode;
   	
 				int              ready = 0;
@@ -2258,32 +2244,29 @@
 				 *  arrived we reset the I/O old PSW to its
 				 *  original value.
 				 */
-				memcpy( &io_new_psw,
-				        &lc->io_new_psw,
-				        sizeof(psw_t));
 
 				ccode = iac();
 
 				switch (ccode) {
 				case 0:  		// primary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_PRIM_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_PRIM_SPACE_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 1:			// secondary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_SEC_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_SEC_SPACE_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 2:			// access-register
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_ACC_REG_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask = _IO_PSW_MASK
+						| _PSW_ACC_REG_MODE
+						| _PSW_IO_WAIT;
 					break;
 				case 3:			// home-space	
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_HOME_SPACE_MODE
-					                    | _PSW_IO_WAIT;
+					psw_mask =   _IO_PSW_MASK
+					        | _PSW_HOME_SPACE_MODE
+					        | _PSW_IO_WAIT;
 					break;
 				default:
 					panic( "clear_IO() : unexpected "
@@ -2292,8 +2275,6 @@
 					break;
 				} /* endswitch */
 
-				io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
-
 				/*
 				 * Martin didn't like modifying the new PSW, now we take
 				 *  a fast exit in do_IRQ() instead
@@ -2302,9 +2283,8 @@
 
 				do
 				{
+					__load_psw_mask( psw_mask );
 
-					__load_psw( io_sync_wait );
-cio_wakeup:
 				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
 				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
 
diff -urN linux-2.4.19-pre2/drivers/scsi/cpqfcTSstructs.h linux-2.4.19-pre3/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.19-pre2/drivers/scsi/cpqfcTSstructs.h	Thu Oct 25 13:53:50 2001
+++ linux-2.4.19-pre3/drivers/scsi/cpqfcTSstructs.h	Mon Mar 11 14:13:29 2002
@@ -27,7 +27,7 @@
 
 #define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
                          for( wait_time=jiffies + (secs*HZ); \
-		         wait_time > jiffies ;) ; }
+		         time_before(jiffies, wait_time) ;) ; }
 
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 // don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
diff -urN linux-2.4.19-pre2/drivers/scsi/ide-scsi.c linux-2.4.19-pre3/drivers/scsi/ide-scsi.c
--- linux-2.4.19-pre2/drivers/scsi/ide-scsi.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/scsi/ide-scsi.c	Mon Mar 11 14:13:29 2002
@@ -529,28 +529,35 @@
 	return 0;
 }
 
+int idescsi_reinit(ide_drive_t *drive);
+
 /*
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idescsi_driver = {
-	"ide-scsi",		/* name */
-	IDESCSI_VERSION,	/* version */
-	ide_scsi,		/* media */
-	0,			/* busy */
-	1,			/* supports_dma */
-	0,			/* supports_dsc_overlap */
-	idescsi_cleanup,	/* cleanup */
-	idescsi_do_request,	/* do_request */
-	idescsi_end_request,	/* end_request */
-	NULL,			/* ioctl */
-	idescsi_open,		/* open */
-	idescsi_ide_release,	/* release */
-	NULL,			/* media_change */
-	NULL,			/* revalidate */
-	NULL,			/* pre_reset */
-	NULL,			/* capacity */
-	NULL,			/* special */
-	NULL			/* proc */
+	name:			"ide-scsi",
+	version:		IDESCSI_VERSION,
+	media:			ide_scsi,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
+	cleanup:		idescsi_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
+	do_request:		idescsi_do_request,
+	end_request:		idescsi_end_request,
+	ioctl:			NULL,
+	open:			idescsi_open,
+	release:		idescsi_ide_release,
+	media_change:		NULL,
+	revalidate:		NULL,
+	pre_reset:		NULL,
+	capacity:		NULL,
+	special:		NULL,
+	proc:			NULL,
+	reinit:			idescsi_reinit,
+	ata_prebuilder:		NULL,
+	atapi_prebuilder:	NULL,
 };
 
 int idescsi_init (void);
@@ -561,6 +568,43 @@
 	NULL
 };
 
+int idescsi_reinit (ide_drive_t *drive)
+{
+#if 0
+	idescsi_scsi_t *scsi;
+	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	int i, failed, id;
+
+	if (!idescsi_initialized)
+		return 0;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+
+	MOD_INC_USE_COUNT;
+	for (i = 0; media[i] != 255; i++) {
+		failed = 0;
+		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+				continue;
+			}
+			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
+				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+				kfree (scsi);
+				continue;
+			}
+			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
+				idescsi_setup (drive, scsi, id);
+			failed--;
+		}
+	}
+	ide_register_module(&idescsi_module);
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
 /*
  *	idescsi_init will register the driver for each scsi.
  */
@@ -591,7 +635,7 @@
 				continue;
 			}
 			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-			idescsi_setup (drive, scsi, id);
+				idescsi_setup (drive, scsi, id);
 			failed--;
 		}
 	}
diff -urN linux-2.4.19-pre2/drivers/scsi/scsi_debug.c linux-2.4.19-pre3/drivers/scsi/scsi_debug.c
--- linux-2.4.19-pre2/drivers/scsi/scsi_debug.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre3/drivers/scsi/scsi_debug.c	Mon Mar 11 14:13:29 2002
@@ -14,7 +14,7 @@
  *
  *   D. Gilbert (dpg) work for MOD device test [20010421]
  *   dpg, work for devfs large number of disks [20010809]
- *   dpg, make more generic [20011123]
+ *   dpg, use vmalloc() more inquiry+mode_sense [20020302]
  */
 
 #include <linux/config.h>
@@ -45,7 +45,7 @@
 #include <linux/version.h>
 #endif
 
-static char scsi_debug_version_str[] = "Version: 0.57 (20011209)";
+static char scsi_debug_version_str[] = "Version: 0.58 (20020302)";
 
 #ifndef SCSI_CMD_READ_16
 #define SCSI_CMD_READ_16 0x88
@@ -59,22 +59,26 @@
 #define DEF_DEV_SIZE_MB   8
 #define DEF_FAKE_BLK0   0
 
+#define DEF_OPTS   0
+#define SCSI_DEBUG_OPT_NOISE   1
+#define SCSI_DEBUG_OPT_MEDIUM_ERR   2
+
+#define OPT_MEDIUM_ERR_ADDR   0x1234
+
 static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+static int scsi_debug_opts = DEF_OPTS;
 
 #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
 #define N_HEAD          8
 #define N_SECTOR        32
-#define DISK_READONLY(TGT)      (0)
-#define DISK_REMOVEABLE(TGT)    (0)
+#define DEV_READONLY(TGT)      (0)
+#define DEV_REMOVEABLE(TGT)    (0)
 #define DEVICE_TYPE(TGT) (TYPE_DISK);
 
 #define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
 
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
-#define STORE_ELEM_ORDER 1
-#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
-#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
 
 /* default sector size is 512 bytes, 2**9 bytes */
 #define POW2_SECT_SIZE 9
@@ -82,8 +86,6 @@
 
 #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
 
-static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
-
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
 #define IMMEDIATE
@@ -94,20 +96,14 @@
 #define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
 #define SECT_SIZE_PER(TGT) SECT_SIZE
-#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
 
 static int starts[] =
 {N_SECTOR,
  N_HEAD * N_SECTOR,		/* Single cylinder */
  N_HEAD * N_SECTOR * 4,
  0 /* CAPACITY */, 0};
-static int npart = 0;
 
-typedef struct scsi_debug_store_elem {
-	unsigned char * p;
-} Sd_store_elem;
-
-static Sd_store_elem * store_arr = 0;
+static unsigned char * fake_storep;
 
 typedef struct sdebug_dev_info {
 	Scsi_Device * sdp;
@@ -132,13 +128,18 @@
 
 static volatile done_fct_t * do_done = 0;
 
-struct Scsi_Host * SHpnt = NULL;
+static struct Scsi_Host * SHpnt = NULL;
 
+static int scsi_debug_inquiry(unsigned char * cmd, int target,
+			      unsigned char * buff, int bufflen,
+			      Sdebug_dev_info * devip);
+static int scsi_debug_mode_sense(unsigned char * cmd, int target,
+			         unsigned char * buff, int bufflen,
+			         Sdebug_dev_info * devip);
 static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
 			   int num, int * errstsp, Sdebug_dev_info * devip);
 static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
 			    int num, int * errstsp, Sdebug_dev_info * devip);
-static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
 static void scsi_debug_intr_handle(unsigned long);
 static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
 static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
@@ -157,101 +158,11 @@
 #define SENSE_BUFF_LEN 32
 static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
 
-#ifdef SCSI_DUMP
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
-{
-	int i;
-	unsigned int *lpnt;
-	struct scatterlist *sgpnt = NULL;
-	printk("use_sg: %d", SCpnt->use_sg);
-	if (SCpnt->use_sg) {
-		sgpnt = (struct scatterlist *) SCpnt->buffer;
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			lpnt = (int *) sgpnt[i].alt_address;
-			printk(":%p %p %d\n", sgpnt[i].alt_address, 
-			       sgpnt[i].address, sgpnt[i].length);
-			if (lpnt)
-				printk(" (Alt %x) ", lpnt[15]);
-		}
-	} else {
-		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
-		       SCpnt->bufflen);
-		lpnt = (int *) SCpnt->request.buffer;
-		if (lpnt)
-			printk(" (Alt %x) ", lpnt[15]);
-	}
-	lpnt = (unsigned int *) SCpnt;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	}
-	printk("\n");
-	if (flag == 0)
-		return;
-	lpnt = (unsigned int *) sgpnt[0].alt_address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	}
-#if 0
-	printk("\n");
-	lpnt = (unsigned int *) sgpnt[0].address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	}
-	printk("\n");
-#endif
-	printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
-}
-#endif
-
-static int made_block0 = 0;
-
-static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
-				Scsi_Cmnd * SCpnt)
-{
-	int i;
-	struct partition *p;
-
-	memset(buff, 0, bufflen);
-	*((unsigned short *) (buff + 510)) = 0xAA55;
-	p = (struct partition *) (buff + 0x1be);
-	i = 0;
-	while (starts[i + 1]) {
-		int start_cyl, end_cyl;
-
-		start_cyl = starts[i] / N_HEAD / N_SECTOR;
-		end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
-		p->boot_ind = 0;
-
-		p->head = (i == 0 ? 1 : 0);
-		p->sector = 1 | ((start_cyl >> 8) << 6);
-		p->cyl = (start_cyl & 0xff);
-
-		p->end_head = N_HEAD - 1;
-		p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
-		p->end_cyl = (end_cyl & 0xff);
-
-		p->start_sect = starts[i];
-		p->nr_sects = starts[i + 1] - starts[i];
-		p->sys_ind = 0x83;	/* Linux ext2 partition */
-		p++;
-		i++;
-	}
-	if (!npart)
-		npart = i;
-	made_block0 = 1;
-	i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
-	memcpy(store_arr[0].p, buff, i);
-}
 
+static
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
-	unchar *cmd = (unchar *) SCpnt->cmnd;
+	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block;
 	int upper_blk;
 	unsigned char *buff;
@@ -263,17 +174,12 @@
 	Sdebug_dev_info * devip = NULL;
 	char * sbuff;
 
-#ifdef CONFIG_SMP
-        /*
-         * The io_request_lock *must* be held at this point.
-         */
-        if(! spin_is_locked(&io_request_lock))
-        {
-                printk("Warning - io_request_lock is not held in "
-		       "queuecommand\n");
-        }
-#endif
-
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: queue_command: cmd ");
+		for (i = 0, num = SCpnt->cmd_len; i < num; ++i)
+	            printk("%02x ", cmd[i]);
+		printk("   use_sg=%d\n", SCpnt->use_sg);
+	}
 	/*
 	 * If we are being notified of the mid-level reposessing a command
 	 * due to timeout, just return.
@@ -282,14 +188,23 @@
 		return 0;
 	}
 
-	buff = (unsigned char *) SCpnt->request_buffer;
+        if (SCpnt->use_sg) { /* just use first element */
+                struct scatterlist *sgpnt = (struct scatterlist *)
+                                                SCpnt->request_buffer;
+
+                buff = sgpnt[0].address;
+                bufflen = sgpnt[0].length;
+                /* READ and WRITE process scatterlist themselves */
+        }
+        else
+                buff = (unsigned char *) SCpnt->request_buffer;
 
         /*
          * If a command comes for the ID of the host itself, just print
          * a silly message and return.
          */
         if(target == 7) {
-                printk("How do you do!\n");
+                printk(KERN_WARNING "How do you do!\n");
                 SCpnt->result = 0;
                 done(SCpnt);
                 return 0;
@@ -303,7 +218,7 @@
 #if 0
 	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
 	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
-	       SCpnt->device, (int)(unsigned char)*cmd);
+	       SCpnt->device, (int)*cmd);
 #endif
 	if (NULL == SCpnt->device->hostdata) {
 		devip = devInfoReg(SCpnt->device);
@@ -317,6 +232,13 @@
 	devip = SCpnt->device->hostdata;
 
 	switch (*cmd) {
+	case INQUIRY:     /* mandatory */
+		scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, 
+						       bufflen, devip);
+		/* assume INQUIRY called first so setup max_cmd_len */
+		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+		break;
 	case REQUEST_SENSE:	/* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
 		if (devip) {
@@ -354,23 +276,6 @@
 		}
 		scsi_debug_errsts = 0;
 		break;
-	case INQUIRY:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
-		memset(buff, 0, bufflen);
-		buff[0] = DEVICE_TYPE(target);
-		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	
-				/* Removable disk */
-		buff[2] = 2;	/* claim SCSI 2 */
-		buff[4] = 36 - 5;
-		memcpy(&buff[8], "Linux   ", 8);
-		memcpy(&buff[16], "scsi_debug      ", 16);
-		memcpy(&buff[32], "0002", 4);
-		scsi_debug_errsts = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
-		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
-			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
-#endif
-		break;
 	case SEND_DIAGNOSTIC:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
 		if (buff)
@@ -378,7 +283,8 @@
 		scsi_debug_errsts = 0;
 		break;
 	case TEST_UNIT_READY:     /* mandatory */
-		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
+		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", 
+					   buff, bufflen));
 		if (buff)
 			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
@@ -484,19 +390,15 @@
 		(done) (SCpnt);	
 		return 0;
 	case MODE_SENSE:
-		/*
-		 * Used to detect write protected status.
-		 */
-		scsi_debug_errsts = 0;
-		memset(buff, 0, 6);
+	case MODE_SENSE_10:
+		scsi_debug_errsts = 
+		    scsi_debug_mode_sense(cmd, target, buff, bufflen, devip);
 		break;
 	default:
 #if 0
-		SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		return 0;
-#else
+		printk(KERN_INFO "scsi_debug: Unsupported command, "
+		       "opcode=0x%x\n", (int)cmd[0]);
+#endif
 		if (check_reset(SCpnt, devip)) {
 			done(SCpnt);
 			return 0;
@@ -505,7 +407,6 @@
 				    (CHECK_CONDITION << 1);
 		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
 		break;
-#endif
 	}
 
 	spin_lock_irqsave(&mailbox_lock, iflags);
@@ -545,10 +446,11 @@
 	spin_unlock_irqrestore(&mailbox_lock, iflags);
 	add_timer(&timeout[i]);
 	if (!done)
-		printk("scsi_debug_queuecommand: done can't be NULL\n");
+		printk(KERN_ERR "scsi_debug_queuecommand: "
+		       "done can't be NULL\n");
 
 #if 0
-	printk("Sending command (%d %x %d %d)...", i, done, 
+	printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, 
 	       timeout[i].expires, jiffies);
 #endif
 #endif
@@ -556,6 +458,14 @@
 	return 0;
 }
 
+static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
+{
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
+	}
+	return -ENOTTY;
+}
+
 static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
 {
 	if (devip->reset) {
@@ -568,6 +478,190 @@
 	return 0;
 }
 
+#define SDEBUG_MAX_INQ_SZ 58
+
+static int scsi_debug_inquiry(unsigned char * cmd, int target,
+			      unsigned char * buff, int bufflen,
+			      Sdebug_dev_info * devip)
+{
+	unsigned char pq_pdt;
+	unsigned char arr[SDEBUG_MAX_INQ_SZ];
+	int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? 
+			SDEBUG_MAX_INQ_SZ : bufflen;
+
+	SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
+	if (bufflen < cmd[4])
+		printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d "
+		       "< alloc_length=%d\n", bufflen, (int)cmd[4]);
+	memset(buff, 0, bufflen);
+	memset(arr, 0, SDEBUG_MAX_INQ_SZ);
+	pq_pdt = DEVICE_TYPE(target);
+	arr[0] = pq_pdt;
+	if (0x2 & cmd[1]) {  /* CMDDT bit set */
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+	}
+	else if (0x1 & cmd[1]) {  /* EVPD bit set */
+		if (0 == cmd[2]) { /* supported vital product data pages */
+			arr[3] = 1;
+			arr[4] = 0x80; /* ... only unit serial number */
+		}
+		else if (0x80 == cmd[2]) { /* unit serial number */
+			arr[1] = 0x80;
+			arr[3] = 4;
+			arr[4] = '1'; arr[5] = '2'; arr[6] = '3';
+			arr[7] = '4';
+		}
+		else {
+			/* Illegal request, invalid field in cdb */
+			mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+			return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+		}
+		memcpy(buff, arr, min_len); 
+		return 0;
+	}
+	/* drops through here for a standard inquiry */
+	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
+	arr[2] = 3;	/* claim SCSI 3 */
+	arr[4] = SDEBUG_MAX_INQ_SZ - 5;
+	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
+	memcpy(&arr[8], "Linux   ", 8);
+	memcpy(&arr[16], "scsi_debug      ", 16);
+	memcpy(&arr[32], "0003", 4);
+	memcpy(buff, arr, min_len);
+	return 0;
+}
+
+/* <<Following mode page info copied from ST318451LW>> */ 
+
+static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target)
+{	/* Read-Write Error Recovery page for mode_sense */
+	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 
+					5, 0, 0xff, 0xff};
+
+	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
+	return sizeof(err_recov_pg);
+}
+
+static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Disconnect-Reconnect page for mode_sense */
+	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 
+					 0, 0, 0, 0, 0, 0, 0, 0};
+
+	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
+	return sizeof(disconnect_pg);
+}
+
+static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Caching page for mode_sense */
+	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 
+		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
+
+	memcpy(p, caching_pg, sizeof(caching_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(caching_pg) - 2);
+	return sizeof(caching_pg);
+}
+
+static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Control mode page for mode_sense */
+	unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+				     0, 0, 0x2, 0x4b};
+
+	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
+	return sizeof(ctrl_m_pg);
+}
+
+
+#define SDEBUG_MAX_MSENSE_SZ 256
+
+static int scsi_debug_mode_sense(unsigned char * cmd, int target,
+			         unsigned char * buff, int bufflen,
+			         Sdebug_dev_info * devip)
+{
+	unsigned char dbd;
+	int pcontrol, pcode;
+	unsigned char dev_spec;
+	int alloc_len, msense_6, offset, len;
+	unsigned char * ap;
+	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
+	int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? 
+			SDEBUG_MAX_MSENSE_SZ : bufflen;
+
+	SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen));
+	dbd = cmd[1] & 0x8;
+	pcontrol = (cmd[2] & 0xc0) >> 6;
+	pcode = cmd[2] & 0x3f;
+	msense_6 = (MODE_SENSE == cmd[0]);
+	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[6]);
+	/* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d "
+		"msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, "
+		"msense_6, alloc_len); */
+	if (bufflen < alloc_len)
+		printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d "
+		       "< alloc_length=%d\n", bufflen, alloc_len);
+	memset(buff, 0, bufflen);
+	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
+	if (0x3 == pcontrol) {  /* Saving values not supported */
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+	}
+	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
+	if (msense_6) {
+		arr[2] = dev_spec;
+		offset = 4;
+	}
+	else {
+		arr[3] = dev_spec;
+		offset = 8;
+	}
+	ap = arr + offset;
+
+	switch (pcode) {
+	case 0x1:	/* Read-Write error recovery page, direct access */
+		len = sdebug_err_recov_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x2:	/* Disconnect-Reconnect page, all devices */
+		len = sdebug_disconnect_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x8:	/* Caching page, direct access */
+		len = sdebug_caching_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0xa:	/* Control Mode page, all devices */
+		len = sdebug_ctrl_m_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x3f:	/* Read all Mode pages */
+		len = sdebug_err_recov_pg(ap, pcontrol, target);
+		len += sdebug_disconnect_pg(ap + len, pcontrol, target);
+		len += sdebug_caching_pg(ap + len, pcontrol, target);
+		len += sdebug_ctrl_m_pg(ap + len, pcontrol, target);
+		offset += len;
+		break;
+	default:
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14);
+		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+	}
+	if (msense_6)
+		arr[0] = offset - 1;
+	else {
+		offset -= 2;
+		arr[0] = (offset >> 8) & 0xff; 
+		arr[1] = offset & 0xff; 
+	}
+	memcpy(buff, arr, min_len);
+	return 0;
+}
+
 static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
 			   int num, int * errstsp, Sdebug_dev_info * devip)
 {
@@ -592,11 +686,19 @@
 			usleep(delay);
 	}
 #endif
-
+	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
+	    (block >= OPT_MEDIUM_ERR_ADDR) && 
+	    (block < (OPT_MEDIUM_ERR_ADDR + num))) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14);
+		/* claim unrecoverable read error */
+		return 1;
+	}
 	read_lock_irqsave(&sdebug_atomic_rw, iflags);
         sgcount = 0;
 	nbytes = bufflen;
-	/* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", 
+	/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", 
 	       block, bufflen); */
 	if (SCpnt->use_sg) {
 		sgcount = 0;
@@ -606,30 +708,7 @@
 	}
 	*errstsp = 0;
 	do {
-		int resid, k, off, len, rem, blk;
-		unsigned char * bp;
-
-		/* If this is block 0, then we want to read the partition
-		 * table for this device.  Let's make one up */
-		if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
-			scsi_debug_mkblock0(buff, bufflen, SCpnt);
-			*errstsp = 0;
-			break;
-		}
-		bp = buff;
-		blk = block;
-		for (resid = bufflen; resid > 0; resid -= len) {
-			k = blk / SECT_PER_ELEM; 
-			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
-			rem = STORE_ELEM_SIZE - off;
-			len = (resid > rem) ? rem : resid;
-/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
-			       "=%d len=%d  sgcount=%d\n", blk, k, 
-				off, rem, resid, len, sgcount); */
-			memcpy(bp, store_arr[k].p + off, len);
-			bp += len;
-			blk += len / SECT_SIZE;
-		}
+		memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen);
 #if 0
 		/* Simulate a disk change */
 		if (block == 0xfff0) {
@@ -655,7 +734,8 @@
 			}
 		}
 		else if (nbytes > 0)
-			printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+			printk(KERN_WARNING "sdebug_read: unexpected "
+			       "nbytes=%d\n", nbytes);
 	} while (nbytes);
 	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
 	return 0;
@@ -679,13 +759,6 @@
 
 	write_lock_irqsave(&sdebug_atomic_rw, iflags);
         sgcount = 0;
-#ifdef SCSI_DUMP
-	if (block != *((unsigned long *) (buff + 60))) {
-		printk("%x %x :", block, *((unsigned long *) (buff + 60)));
-		scsi_dump(SCpnt, 1);
-		printk("Bad block written.\n");
-	}
-#endif
 	nbytes = bufflen;
 	if (SCpnt->use_sg) {
 		sgcount = 0;
@@ -695,20 +768,7 @@
 	}
 	*errstsp = 0;
 	do {
-		int resid, k, off, len, rem, blk;
-		unsigned char * bp;
-
-		bp = buff;
-		blk = block;
-		for (resid = bufflen; resid > 0; resid -= len) {
-			k = blk / SECT_PER_ELEM; 
-			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
-			rem = STORE_ELEM_SIZE - off;
-			len = (resid > rem) ? rem : resid;
-			memcpy(store_arr[k].p + off, bp, len);
-			bp += len;
-			blk += len / SECT_SIZE;
-		}
+		memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen);
 
 		nbytes -= bufflen;
 		if (SCpnt->use_sg) {
@@ -720,52 +780,13 @@
 			}
 		}
 		else if (nbytes > 0)
-			printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+			printk(KERN_WARNING "sdebug_write: "
+			       "unexpected nbytes=%d\n", nbytes);
 	} while (nbytes);
 	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
 	return 0;
 }
 
-static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
-{
-	static unsigned char cmd[6] =
-	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
-
-        Scsi_Request  * scp;
-        Scsi_Device   * sdev;
-        
-        printk("Allocating host dev\n");
-        sdev = scsi_get_host_dev(shpnt);
-        if(sdev==NULL)
-        {
-        	printk("Out of memory.\n");
-        	return;
-        }
-        
-        printk("Got %p. Allocating command block\n", sdev);
-        scp  = scsi_allocate_request(sdev);
-        printk("Got %p\n", scp);
-        
-        if(scp==NULL)
-        {
-        	printk("Out of memory.\n");
-        	goto bail;
-        }
-
-        scp->sr_cmd_len = 6;
-        scp->sr_use_sg = 0;
-        
-        printk("Sending command\n");
-        scsi_wait_req (scp, (void *) cmd, (void *) NULL,
-                       0, 100, 3);
-        
-        printk("Releasing command\n");
-        scsi_release_request(scp);
-bail:
-	printk("Freeing device\n");
-        scsi_free_host_dev(sdev);
-}
-
 /* A "high" level interrupt handler.  This should be called once per jiffy
  * to simulate a regular scsi disk.  We use a timer to do this. */
 
@@ -784,18 +805,19 @@
 	SCint[indx] = NULL;
 
 	if (!my_done) {
-		printk("scsi_debug_intr_handle: Unexpected interrupt\n");
+		printk(KERN_ERR "scsi_debug_intr_handle: Unexpected "
+		       "interrupt\n");
 		return;
 	}
 #if 0
-	printk("In intr_handle...");
-	printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
-	printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
+	printk(KERN_INFO "In intr_handle...");
+	printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies);
+	printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
 
 	my_done(SCtmp);
 #if 0
-	printk("Called done.\n");
+	printk(KERN_INFO "Called done.\n");
 #endif
 }
 
@@ -803,39 +825,44 @@
 
 static int do_init(void)
 {
-	int sz;
+	int sz = STORE_SIZE;
 
 	starts[3] = CAPACITY;
-	sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
-	store_arr = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == store_arr)
+	fake_storep = vmalloc(sz);
+	if (NULL == fake_storep)
 		return 1;
-	memset(store_arr, 0, sz);
+	memset(fake_storep, 0, sz);
+
 	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
 	do_done = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == do_done) {
-		kfree(store_arr);
-		return 1;
-	}
+	if (NULL == do_done)
+		goto out;
 	memset((void *)do_done, 0, sz);
+
 	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
 	timeout = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == timeout) {
-		kfree((void *)do_done);
-		kfree(store_arr);
-		return 1;
-	}
+	if (NULL == timeout)
+		goto out;
 	memset(timeout, 0, sz);
+
 	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
 	SCint = kmalloc(sz, GFP_ATOMIC);
-	if (NULL == SCint) {
-		kfree(timeout);
-		kfree((void *)do_done);
-		kfree(store_arr);
-		return 1;
-	}
+	if (NULL == SCint)
+		goto out;
 	memset(SCint, 0, sz);
+
 	return 0;
+
+out:
+	if (fake_storep)
+		vfree(fake_storep);
+	if (do_done)
+		kfree((void *)do_done);
+	if (timeout)
+		kfree(timeout);
+	if (SCint)
+		kfree(SCint);
+	return 1;
 }
 
 static void do_end(void)
@@ -843,34 +870,31 @@
 	kfree(SCint);
 	kfree(timeout);
 	kfree((void *)do_done);
-	kfree(store_arr);
+	vfree(fake_storep);
 }
 
 
-int scsi_debug_detect(Scsi_Host_Template * tpnt)
+static int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-	int k, num, sz;
+	int k, sz;
 
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: detect\n");
 	if (0 == initialized) {
 		++initialized;
 		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
 		devInfop = kmalloc(sz, GFP_ATOMIC);
 		if (NULL == devInfop) {
-			printk("scsi_debug_detect: out of memory, 0.5\n");
+			printk(KERN_ERR "scsi_debug_detect: out of "
+			       "memory, 0.5\n");
 			return 0;
 		}
 		memset(devInfop, 0, sz);
 		if (do_init()) {
-			printk("scsi_debug_detect: out of memory, 0\n");
+			printk(KERN_ERR "scsi_debug_detect: out of memory"
+			       ", 0\n");
 			return 0;
 		}
-		for (k = 0; k < STORE_ELEMENTS; ++k) {
-			store_arr[k].p = (unsigned char *)
-				__get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
-			if (0 == store_arr[k].p)
-				goto detect_err;
-			memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
-		}
 		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
 			sense_buffers[k][0] = 0x70;
 		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
@@ -880,43 +904,21 @@
 		return NR_HOSTS_PRESENT;
 	}
 	else {
-		printk("scsi_debug_detect: called again\n");
+		printk(KERN_WARNING "scsi_debug_detect: called again\n");
 		return 0;
 	}
-
-detect_err:
-	num = k;
-	for (k = 0; k < STORE_ELEMENTS; ++k) {
-		if (0 != store_arr[k].p) {
-			free_pages((unsigned long)store_arr[k].p, 
-				   STORE_ELEM_ORDER);
-			store_arr[k].p = NULL;
-		}
-	}
-	printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
-	       (int)(num * STORE_ELEM_SIZE), 
-	       (int)(scsi_debug_dev_size_mb * 1024 * 1024));
-	return 0;
 }
 
 
 static int num_releases = 0;
 
-int scsi_debug_release(struct Scsi_Host * hpnt)
+static int scsi_debug_release(struct Scsi_Host * hpnt)
 {
-	int k;
-	
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: release\n");
 	scsi_unregister(hpnt);
 	if (++num_releases != NR_HOSTS_PRESENT)
 		return 0;
-
-	for (k = 0; k < STORE_ELEMENTS; ++k) {
-		if (0 != store_arr[k].p) {
-			free_pages((unsigned long)store_arr[k].p, 
-				   STORE_ELEM_ORDER);
-			store_arr[k].p = NULL;
-		}
-	}
 	do_end();
 	kfree(devInfop);
 	return 0;
@@ -966,8 +968,10 @@
 	sbuff[13] = asq;
 }
 
-int scsi_debug_abort(Scsi_Cmnd * SCpnt)
+static int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: abort\n");
 #if 1
 	++num_aborts;
 	return SUCCESS;
@@ -991,8 +995,10 @@
 #endif
 }
 
-int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
+static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: biosparam\n");
 	/* int size = disk->capacity; */
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
@@ -1002,36 +1008,13 @@
 	return 0;
 }
 
-#if 0
-int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
-{
-	int i;
-	unsigned long iflags;
-
-	void (*my_done) (Scsi_Cmnd *);
-	printk("Bus unlocked by reset - %d\n", why);
-	scsi_debug_lockup = 0;
-	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
-		if (SCint[i] == NULL)
-			continue;
-		SCint[i]->result = DID_RESET << 16;
-		my_done = do_done[i];
-		my_done(SCint[i]);
-		spin_lock_irqsave(&mailbox_lock, iflags);
-		SCint[i] = NULL;
-		do_done[i] = NULL;
-		timeout[i].function = NULL;
-		spin_unlock_irqrestore(&mailbox_lock, iflags);
-	}
-	return SCSI_RESET_SUCCESS;
-}
-#endif
-
-int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
 {
 	Scsi_Device * sdp;
 	int k;
 
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: device_reset\n");
 	++num_dev_resets;
 	if (SCpnt && ((sdp = SCpnt->device))) {
 		for (k = 0; k < scsi_debug_num_devs; ++k) {
@@ -1044,12 +1027,14 @@
 	return SUCCESS;
 }
 
-int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
 {
 	Scsi_Device * sdp;
 	struct Scsi_Host * hp;
 	int k;
 
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: bus_reset\n");
 	++num_bus_resets;
 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
 		for (k = 0; k < scsi_debug_num_devs; ++k) {
@@ -1060,10 +1045,12 @@
 	return SUCCESS;
 }
 
-int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
 {
 	int k;
 
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: host_reset\n");
 	++num_host_resets;
 	for (k = 0; k < scsi_debug_num_devs; ++k)
 		devInfop[k].reset = 1;
@@ -1081,7 +1068,7 @@
             scsi_debug_num_devs = tmp;
         return 1;
     } else {
-        printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+        printk(KERN_INFO "scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
                "(<n> can be from 1 to around 2000)\n");
         return 0;
     }
@@ -1098,13 +1085,32 @@
             scsi_debug_dev_size_mb = tmp;
         return 1;
     } else {
-        printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+        printk(KERN_INFO "scsi_debug_dev_size_mb: usage "
+	       "scsi_debug_dev_size_mb=<n>\n"
                "    (<n> is number of MB ram shared by all devs\n");
         return 0;
     }
 }
 
 __setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+
+static int __init scsi_debug_opts_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_opts = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_opts: usage "
+	       "scsi_debug_opts=<n>\n"
+               "    (1->noise, 2->medium_error, 4->... (can be or-ed)\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_opts=", scsi_debug_opts_setup);
 #endif
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
@@ -1113,6 +1119,8 @@
 MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
 MODULE_PARM(scsi_debug_dev_size_mb, "i");
 MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+MODULE_PARM(scsi_debug_opts, "i");
+MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->...");
 
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
@@ -1123,8 +1131,9 @@
 const char * scsi_debug_info(struct Scsi_Host * shp)
 {
 	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
-		"dev_size_mb=%d\n", scsi_debug_version_str,
-		scsi_debug_num_devs, scsi_debug_dev_size_mb);
+		"dev_size_mb=%d, opts=0x%x", scsi_debug_version_str,
+		scsi_debug_num_devs, scsi_debug_dev_size_mb,
+		scsi_debug_opts);
 	return sdebug_info;
 }
 
@@ -1140,55 +1149,28 @@
 	orig_length = length;
 
 	if (inout == 1) {
-		/* First check for the Signature */
-		if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
-			buffer += 11;
-			length -= 11;
-
-			if (buffer[length - 1] == '\n') {
-				buffer[length - 1] = '\0';
-				length--;
-			}
-			/*
-			 * OK, we are getting some kind of command.  Figure out
-			 * what we are supposed to do here.  Simulate bus lockups
-			 * to test our reset capability.
-			 */
-			if (length == 4 && strncmp(buffer, "test", length) == 0) {
-                                printk("Testing send self command %p\n", SHpnt);
-                                scsi_debug_send_self_command(SHpnt);
-                                return orig_length;
-                        }
-			if (length == 6 && strncmp(buffer, "lockup", length) == 0) {
-				scsi_debug_lockup = 1;
-				return orig_length;
-			}
-			if (length == 6 && strncmp(buffer, "unlock", length) == 0) {
-				scsi_debug_lockup = 0;
-				return orig_length;
-			}
-			printk("Unknown command:%s (%d)\n", buffer, length);
-		} else
-			printk("Wrong Signature:%10s\n", (char *) buffer);
-
-		return -EINVAL;
+		char arr[16];
+		int minLen = length > 15 ? 15 : length;
 
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		memcpy(arr, buffer, minLen);
+		arr[minLen] = '\0';
+		if (1 != sscanf(arr, "%d", &pos))
+			return -EINVAL;
+		scsi_debug_opts = pos;
+		return length;
 	}
 	begin = 0;
 	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
-	    "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" 
-	    "cylinders=%d, heads=%d, sectors=%d\n"
+	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
 	    "host_resets=%d\n",
 	    scsi_debug_version_str, scsi_debug_num_devs, 
-	    scsi_debug_dev_size_mb, SECT_SIZE,
+	    scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE,
 	    N_CYLINDER, N_HEAD, N_SECTOR,
 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
-#if 0
-	 "This driver is not a real scsi driver, but it plays one on TV.\n"
-	 "It is very handy for debugging specific problems because you\n"
-			 "can simulate a variety of error conditions\n");
-#endif
 	if (pos < offset) {
 		len = 0;
 		begin = pos;
diff -urN linux-2.4.19-pre2/drivers/scsi/scsi_debug.h linux-2.4.19-pre3/drivers/scsi/scsi_debug.h
--- linux-2.4.19-pre2/drivers/scsi/scsi_debug.h	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre3/drivers/scsi/scsi_debug.h	Mon Mar 11 14:13:29 2002
@@ -3,24 +3,23 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 
-int scsi_debug_detect(Scsi_Host_Template *);
-int scsi_debug_command(Scsi_Cmnd *);
-int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int scsi_debug_abort(Scsi_Cmnd *);
-int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_bus_reset(Scsi_Cmnd *);
-int scsi_debug_dev_reset(Scsi_Cmnd *);
-int scsi_debug_host_reset(Scsi_Cmnd *);
-int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
-const char * scsi_debug_info(struct Scsi_Host *);
+static int scsi_debug_detect(Scsi_Host_Template *);
+/* static int scsi_debug_command(Scsi_Cmnd *); */
+static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int scsi_debug_abort(Scsi_Cmnd *);
+static int scsi_debug_biosparam(Disk *, kdev_t, int[]);
+static int scsi_debug_bus_reset(Scsi_Cmnd *);
+static int scsi_debug_device_reset(Scsi_Cmnd *);
+static int scsi_debug_host_reset(Scsi_Cmnd *);
+static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+static const char * scsi_debug_info(struct Scsi_Host *);
 
 #ifndef NULL
 #define NULL 0
 #endif
 
 /*
- * Allow the driver to reject commands.  Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.4 series
  */
 #define SCSI_DEBUG_CANQUEUE  255
 
@@ -32,6 +31,7 @@
 		    info:              scsi_debug_info,		\
 		    detect:            scsi_debug_detect,	\
 		    release:           scsi_debug_release,	\
+		    ioctl:             scsi_debug_ioctl,	\
 		    queuecommand:      scsi_debug_queuecommand, \
 		    eh_abort_handler:  scsi_debug_abort,	\
 		    eh_bus_reset_handler: scsi_debug_bus_reset,	\
diff -urN linux-2.4.19-pre2/drivers/scsi/sym53c8xx.c linux-2.4.19-pre3/drivers/scsi/sym53c8xx.c
--- linux-2.4.19-pre2/drivers/scsi/sym53c8xx.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/scsi/sym53c8xx.c	Mon Mar 11 14:13:29 2002
@@ -14111,7 +14111,7 @@
 	if (len)
 		return -EINVAL;
 	else {
-		long flags;
+		unsigned long flags;
 
 		NCR_LOCK_NCB(np, flags);
 		ncr_usercmd (np);
diff -urN linux-2.4.19-pre2/drivers/sound/Config.in linux-2.4.19-pre3/drivers/sound/Config.in
--- linux-2.4.19-pre2/drivers/sound/Config.in	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/sound/Config.in	Mon Mar 11 14:13:29 2002
@@ -51,7 +51,9 @@
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate '  SGI Visual Workstation sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
 fi
-dep_tristate '  SGI HAL2 sound (EXPERIMENTAL)' CONFIG_SOUND_HAL2 $CONFIG_SOUND $CONFIG_SGI_IP22 $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_SGI_IP22" = "y" ] ; then
+   dep_tristate '  SGI HAL2 sound (EXPERIMENTAL)' CONFIG_SOUND_HAL2 $CONFIG_SOUND $CONFIG_SGI_IP22 $CONFIG_EXPERIMENTAL
+fi
 
 if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
     dep_tristate '  IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND
diff -urN linux-2.4.19-pre2/drivers/sound/nec_vrc5477.c linux-2.4.19-pre3/drivers/sound/nec_vrc5477.c
--- linux-2.4.19-pre2/drivers/sound/nec_vrc5477.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/sound/nec_vrc5477.c	Mon Mar 11 14:13:29 2002
@@ -818,12 +818,6 @@
 
 /* --------------------------------------------------------------------- */
 
-static loff_t vrc5477_ac97_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-
 static int vrc5477_ac97_open_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
@@ -865,7 +859,7 @@
 
 static /*const*/ struct file_operations vrc5477_ac97_mixer_fops = {
 	owner:		THIS_MODULE,
-	llseek:		vrc5477_ac97_llseek,
+	llseek:		no_llseek,
 	ioctl:		vrc5477_ac97_ioctl_mixdev,
 	open:		vrc5477_ac97_open_mixdev,
 	release:	vrc5477_ac97_release_mixdev,
@@ -1631,7 +1625,7 @@
 
 static /*const*/ struct file_operations vrc5477_ac97_audio_fops = {
 	owner:	THIS_MODULE,
-	llseek:		vrc5477_ac97_llseek,
+	llseek:		no_llseek,
 	read:		vrc5477_ac97_read,
 	write:		vrc5477_ac97_write,
 	poll:		vrc5477_ac97_poll,
diff -urN linux-2.4.19-pre2/drivers/usb/auerswald.c linux-2.4.19-pre3/drivers/usb/auerswald.c
--- linux-2.4.19-pre2/drivers/usb/auerswald.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/drivers/usb/auerswald.c	Mon Mar 11 14:13:29 2002
@@ -0,0 +1,2196 @@
+/*****************************************************************************/
+/*
+ *      auerswald.c  --  Auerswald PBX/System Telephone usb driver.
+ *
+ *      Copyright (C) 2001  Wolfgang Mües (wmues@nexgo.de)
+ *
+ *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
+ *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ /*****************************************************************************/
+
+/* Standard Linux module include files */
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#undef DEBUG   		/* include debug macros until it's done	*/
+#include <linux/usb.h>
+
+/*-------------------------------------------------------------------*/
+/* Debug support 						     */
+#ifdef DEBUG
+#define dump( adr, len) \
+do {			\
+	unsigned int u;	\
+	printk (KERN_DEBUG); \
+	for (u = 0; u < len; u++) \
+		printk (" %02X", adr[u] & 0xFF); \
+	printk ("\n"); \
+} while (0)
+#else
+#define dump( adr, len)
+#endif
+
+/*-------------------------------------------------------------------*/
+/* Version Information */
+#define DRIVER_VERSION "0.9.11"
+#define DRIVER_AUTHOR  "Wolfgang Mües <wmues@nexgo.de>"
+#define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
+
+/*-------------------------------------------------------------------*/
+/* Private declarations for Auerswald USB driver                     */
+
+/* Auerswald Vendor ID */
+#define ID_AUERSWALD  	0x09BF
+
+#ifndef AUER_MINOR_BASE		/* allow external override */
+#define AUER_MINOR_BASE	112	/* auerswald driver minor number */
+#endif
+
+/* we can have up to this number of device plugged in at once */
+#define AUER_MAX_DEVICES 16
+
+/* prefix for the device descriptors in /dev/usb */
+#define AU_PREFIX	"auer"
+
+/* Number of read buffers for each device */
+#define AU_RBUFFERS     10
+
+/* Number of chain elements for each control chain */
+#define AUCH_ELEMENTS   20
+
+/* Number of retries in communication */
+#define AU_RETRIES	10
+
+/*-------------------------------------------------------------------*/
+/* vendor specific protocol                                          */
+/* Header Byte */
+#define AUH_INDIRMASK   0x80    /* mask for direct/indirect bit */
+#define AUH_DIRECT      0x00    /* data is for USB device */
+#define AUH_INDIRECT    0x80    /* USB device is relay */
+
+#define AUH_SPLITMASK   0x40    /* mask for split bit */
+#define AUH_UNSPLIT     0x00    /* data block is full-size */
+#define AUH_SPLIT       0x40    /* data block is part of a larger one,
+                                   split-byte follows */
+
+#define AUH_TYPEMASK    0x3F    /* mask for type of data transfer */
+#define AUH_TYPESIZE    0x40    /* different types */
+#define AUH_DCHANNEL    0x00    /* D channel data */
+#define AUH_B1CHANNEL   0x01    /* B1 channel transparent */
+#define AUH_B2CHANNEL   0x02    /* B2 channel transparent */
+/*                0x03..0x0F       reserved for driver internal use */
+#define AUH_COMMAND     0x10    /* Command channel */
+#define AUH_BPROT       0x11    /* Configuration block protocol */
+#define AUH_DPROTANA    0x12    /* D channel protocol analyzer */
+#define AUH_TAPI        0x13    /* telephone api data (ATD) */
+/*                0x14..0x3F       reserved for other protocols */
+#define AUH_UNASSIGNED  0xFF    /* if char device has no assigned service */
+#define AUH_FIRSTUSERCH 0x11    /* first channel which is available for driver users */
+
+#define AUH_SIZE	1 	/* Size of Header Byte */
+
+/* Split Byte. Only present if split bit in header byte set.*/
+#define AUS_STARTMASK   0x80    /* mask for first block of splitted frame */
+#define AUS_FIRST       0x80    /* first block */
+#define AUS_FOLLOW      0x00    /* following block */
+
+#define AUS_ENDMASK     0x40    /* mask for last block of splitted frame */
+#define AUS_END         0x40    /* last block */
+#define AUS_NOEND       0x00    /* not the last block */
+
+#define AUS_LENMASK     0x3F    /* mask for block length information */
+
+/* Request types */
+#define AUT_RREQ        (USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Read Request */
+#define AUT_WREQ        (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Write Request */
+
+/* Vendor Requests */
+#define AUV_GETINFO     0x00    /* GetDeviceInfo */
+#define AUV_WBLOCK      0x01    /* Write Block */
+#define AUV_RBLOCK      0x02    /* Read Block */
+#define AUV_CHANNELCTL  0x03    /* Channel Control */
+#define AUV_DUMMY	0x04	/* Dummy Out for retry */
+
+/* Device Info Types */
+#define AUDI_NUMBCH     0x0000  /* Number of supported B channels */
+#define AUDI_OUTFSIZE   0x0001  /* Size of OUT B channel fifos */
+#define AUDI_MBCTRANS   0x0002  /* max. Blocklength of control transfer */
+
+/* Interrupt endpoint definitions */
+#define AU_IRQENDP      1       /* Endpoint number */
+#define AU_IRQCMDID     16      /* Command-block ID */
+#define AU_BLOCKRDY     0       /* Command: Block data ready on ctl endpoint */
+#define AU_IRQMINSIZE	5	/* Nr. of bytes decoded in this driver */
+
+/* Device String Descriptors */
+#define AUSI_VENDOR   	1	/* "Auerswald GmbH & Co. KG" */
+#define AUSI_DEVICE   	2	/* Name of the Device */
+#define AUSI_SERIALNR 	3	/* Serial Number */
+#define AUSI_MSN      	4	/* "MSN ..." (first) Multiple Subscriber Number */
+
+#define AUSI_DLEN	100	/* Max. Length of Device Description */
+
+#define AUV_RETRY	0x101	/* First Firmware version which can do control retries */
+
+/*-------------------------------------------------------------------*/
+/* External data structures / Interface                              */
+typedef struct
+{
+        char *buf;               /* return buffer for string contents */
+        unsigned int bsize;      /* size of return buffer */
+} audevinfo_t,*paudevinfo_t;
+
+/* IO controls */
+#define IOCTL_AU_SLEN	  _IOR( 'U', 0xF0, int)         /* return the max. string descriptor length */
+#define IOCTL_AU_DEVINFO  _IOWR('U', 0xF1, audevinfo_t) /* get name of a specific device */
+#define IOCTL_AU_SERVREQ  _IOW( 'U', 0xF2, int) 	/* request a service channel */
+#define IOCTL_AU_BUFLEN	  _IOR( 'U', 0xF3, int)         /* return the max. buffer length for the device */
+#define IOCTL_AU_RXAVAIL  _IOR( 'U', 0xF4, int)         /* return != 0 if Receive Data available */
+#define IOCTL_AU_CONNECT  _IOR( 'U', 0xF5, int)         /* return != 0 if connected to a service channel */
+#define IOCTL_AU_TXREADY  _IOR( 'U', 0xF6, int)         /* return != 0 if Transmitt channel ready to send */
+/*                              'U'  0xF7..0xFF reseved */
+
+/*-------------------------------------------------------------------*/
+/* Internal data structures                                          */
+
+/* ..................................................................*/
+/* urb chain element */
+struct  auerchain;                      /* forward for circular reference */
+typedef struct
+{
+        struct auerchain *chain;        /* pointer to the chain to which this element belongs */
+        urb_t * urbp;                   /* pointer to attached urb */
+        void *context;                  /* saved URB context */
+        usb_complete_t complete;        /* saved URB completion function */
+        struct list_head list;          /* to include element into a list */
+} auerchainelement_t,*pauerchainelement_t;
+
+/* urb chain */
+typedef struct auerchain
+{
+        pauerchainelement_t active;     /* element which is submitted to urb */
+	spinlock_t lock;                /* protection agains interrupts */
+        struct list_head waiting_list;  /* list of waiting elements */
+        struct list_head free_list;     /* list of available elements */
+} auerchain_t,*pauerchain_t;
+
+/* urb blocking completion helper struct */
+typedef struct
+{
+	wait_queue_head_t wqh;    	/* wait for completion */
+	unsigned int done;		/* completion flag */
+} auerchain_chs_t,*pauerchain_chs_t;
+
+/* ...................................................................*/
+/* buffer element */
+struct  auerbufctl;                     /* forward */
+typedef struct
+{
+        char *bufp;                     /* reference to allocated data buffer */
+        unsigned int len;               /* number of characters in data buffer */
+	unsigned int retries;		/* for urb retries */
+        devrequest *dr;                 /* for setup data in control messages */
+        urb_t * urbp;                   /* USB urb */
+        struct auerbufctl *list;        /* pointer to list */
+        struct list_head buff_list;     /* reference to next buffer in list */
+} auerbuf_t,*pauerbuf_t;
+
+/* buffer list control block */
+typedef struct auerbufctl
+{
+        spinlock_t lock;                /* protection in interrupt */
+        struct list_head free_buff_list;/* free buffers */
+        struct list_head rec_buff_list; /* buffers with receive data */
+} auerbufctl_t,*pauerbufctl_t;
+
+/* ...................................................................*/
+/* service context */
+struct  auerscon;                       /* forward */
+typedef void (*auer_dispatch_t)(struct auerscon*, pauerbuf_t);
+typedef void (*auer_disconn_t) (struct auerscon*);
+typedef struct auerscon
+{
+        unsigned int id;                /* protocol service id AUH_xxxx */
+        auer_dispatch_t dispatch;       /* dispatch read buffer */
+	auer_disconn_t disconnect;	/* disconnect from device, wake up all char readers */
+} auerscon_t,*pauerscon_t;
+
+/* ...................................................................*/
+/* USB device context */
+typedef struct
+{
+	struct semaphore 	mutex;         	    /* protection in user context */
+	char 			name[16];	    /* name of the /dev/usb entry */
+	unsigned int		dtindex;	    /* index in the device table */
+	devfs_handle_t 		devfs;	 	    /* devfs device node */
+	struct usb_device *	usbdev;      	    /* USB device handle */
+	int			open_count;	    /* count the number of open character channels */
+        char 			dev_desc[AUSI_DLEN];/* for storing a textual description */
+        unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */
+        urb_t * 		inturbp;            /* interrupt urb */
+        char *			intbufp;            /* data buffer for interrupt urb */
+	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */
+        struct auerchain 	controlchain;  	    /* for chaining of control messages */
+	auerbufctl_t 		bufctl;             /* Buffer control for control transfers */
+        pauerscon_t 	     	services[AUH_TYPESIZE];/* context pointers for each service */
+	unsigned int		version;	    /* Version of the device */
+	wait_queue_head_t 	bufferwait;         /* wait for a control buffer */
+} auerswald_t,*pauerswald_t;
+
+/* the global usb devfs handle */
+extern devfs_handle_t usb_devfs_handle;
+
+/* array of pointers to our devices that are currently connected */
+static pauerswald_t dev_table[AUER_MAX_DEVICES];
+
+/* lock to protect the dev_table structure */
+static struct semaphore dev_table_mutex;
+
+/* ................................................................... */
+/* character device context */
+typedef struct
+{
+	struct semaphore mutex;         /* protection in user context */
+	pauerswald_t auerdev;           /* context pointer of assigned device */
+        auerbufctl_t bufctl;            /* controls the buffer chain */
+        auerscon_t scontext;            /* service context */
+	wait_queue_head_t readwait;     /* for synchronous reading */
+	struct semaphore readmutex;     /* protection against multiple reads */
+	pauerbuf_t readbuf;		/* buffer held for partial reading */
+	unsigned int readoffset;	/* current offset in readbuf */
+	unsigned int removed;		/* is != 0 if device is removed */
+} auerchar_t,*pauerchar_t;
+
+
+/*-------------------------------------------------------------------*/
+/* Forwards */
+static void auerswald_ctrlread_complete (urb_t * urb);
+static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
+
+
+/*-------------------------------------------------------------------*/
+/* USB chain helper functions                                        */
+/* --------------------------                                        */
+
+/* completion function for chained urbs */
+static void auerchain_complete (urb_t * urb)
+{
+	unsigned long flags;
+        int result;
+
+        /* get pointer to element and to chain */
+        pauerchainelement_t acep = (pauerchainelement_t) urb->context;
+        pauerchain_t         acp = acep->chain;
+
+        /* restore original entries in urb */
+        urb->context  = acep->context;
+        urb->complete = acep->complete;
+
+        dbg ("auerchain_complete called");
+
+        /* call original completion function
+           NOTE: this function may lead to more urbs submitted into the chain.
+                 (no chain lock at calling complete()!)
+                 acp->active != NULL is protecting us against recursion.*/
+        urb->complete (urb);
+
+        /* detach element from chain data structure */
+	spin_lock_irqsave (&acp->lock, flags);
+        if (acp->active != acep) /* paranoia debug check */
+	        dbg ("auerchain_complete: completion on non-active element called!");
+        else
+                acp->active = NULL;
+
+        /* add the used chain element to the list of free elements */
+	list_add_tail (&acep->list, &acp->free_list);
+        acep = NULL;
+
+        /* is there a new element waiting in the chain? */
+        if (!acp->active && !list_empty (&acp->waiting_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = acp->waiting_list.next;
+                list_del (tmp);
+                acep = list_entry (tmp, auerchainelement_t, list);
+                acp->active = acep;
+        }
+        spin_unlock_irqrestore (&acp->lock, flags);
+
+        /* submit the new urb */
+        if (acep) {
+                urb    = acep->urbp;
+                dbg ("auerchain_complete: submitting next urb from chain");
+		urb->status = 0;	/* needed! */
+		result = usb_submit_urb( urb);
+
+                /* check for submit errors */
+                if (result) {
+                        urb->status = result;
+                        dbg("auerchain_complete: usb_submit_urb with error code %d", result);
+                        /* and do error handling via *this* completion function (recursive) */
+                        auerchain_complete( urb);
+                }
+        } else {
+                /* simple return without submitting a new urb.
+                   The empty chain is detected with acp->active == NULL. */
+        };
+}
+
+
+/* submit function for chained urbs
+   this function may be called from completion context or from user space!
+   early = 1 -> submit in front of chain
+*/
+static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
+{
+        int result;
+        unsigned long flags;
+        pauerchainelement_t acep = NULL;
+
+        dbg ("auerchain_submit_urb called");
+
+        /* try to get a chain element */
+        spin_lock_irqsave (&acp->lock, flags);
+        if (!list_empty (&acp->free_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = acp->free_list.next;
+                list_del (tmp);
+                acep = list_entry (tmp, auerchainelement_t, list);
+        }
+        spin_unlock_irqrestore (&acp->lock, flags);
+
+        /* if no chain element available: return with error */
+        if (!acep) {
+                return -ENOMEM;
+        }
+
+        /* fill in the new chain element values */
+        acep->chain    = acp;
+        acep->context  = urb->context;
+        acep->complete = urb->complete;
+        acep->urbp     = urb;
+        INIT_LIST_HEAD (&acep->list);
+
+        /* modify urb */
+        urb->context   = acep;
+        urb->complete  = auerchain_complete;
+        urb->status    = -EINPROGRESS;    /* usb_submit_urb does this, too */
+
+        /* add element to chain - or start it immediately */
+        spin_lock_irqsave (&acp->lock, flags);
+        if (acp->active) {
+                /* there is traffic in the chain, simple add element to chain */
+		if (early) {
+			dbg ("adding new urb to head of chain");
+			list_add (&acep->list, &acp->waiting_list);
+		} else {
+			dbg ("adding new urb to end of chain");
+			list_add_tail (&acep->list, &acp->waiting_list);
+		}
+		acep = NULL;
+        } else {
+                /* the chain is empty. Prepare restart */
+                acp->active = acep;
+        }
+        /* Spin has to be removed before usb_submit_urb! */
+        spin_unlock_irqrestore (&acp->lock, flags);
+
+        /* Submit urb if immediate restart */
+        if (acep) {
+                dbg("submitting urb immediate");
+		urb->status = 0;	/* needed! */
+                result = usb_submit_urb( urb);
+                /* check for submit errors */
+                if (result) {
+                        urb->status = result;
+                        dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
+                        /* and do error handling via completion function */
+                        auerchain_complete( urb);
+                }
+        }
+
+        return 0;
+}
+
+/* submit function for chained urbs
+   this function may be called from completion context or from user space!
+*/
+static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
+{
+	return auerchain_submit_urb_list (acp, urb, 0);
+}
+
+/* cancel an urb which is submitted to the chain
+   the result is 0 if the urb is cancelled, or -EINPROGRESS if
+   USB_ASYNC_UNLINK is set and the function is successfully started.
+*/
+static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
+{
+	unsigned long flags;
+        urb_t * urbp;
+        pauerchainelement_t acep;
+        struct list_head *tmp;
+
+        dbg ("auerchain_unlink_urb called");
+
+        /* search the chain of waiting elements */
+        spin_lock_irqsave (&acp->lock, flags);
+        list_for_each (tmp, &acp->waiting_list) {
+                acep = list_entry (tmp, auerchainelement_t, list);
+                if (acep->urbp == urb) {
+                        list_del (tmp);
+                        urb->context = acep->context;
+                        urb->complete = acep->complete;
+                        list_add_tail (&acep->list, &acp->free_list);
+                        spin_unlock_irqrestore (&acp->lock, flags);
+                        dbg ("unlink waiting urb");
+                        urb->status = -ENOENT;
+                        urb->complete (urb);
+                        return 0;
+                }
+        }
+        /* not found. */
+        spin_unlock_irqrestore (&acp->lock, flags);
+
+        /* get the active urb */
+        acep = acp->active;
+        if (acep) {
+                urbp = acep->urbp;
+
+                /* check if we have to cancel the active urb */
+                if (urbp == urb) {
+                        /* note that there is a race condition between the check above
+                           and the unlink() call because of no lock. This race is harmless,
+                           because the usb module will detect the unlink() after completion.
+                           We can't use the acp->lock here because the completion function
+                           wants to grab it.
+			*/
+                        dbg ("unlink active urb");
+                        return usb_unlink_urb (urbp);
+                }
+        }
+
+        /* not found anyway
+           ... is some kind of success
+	*/
+        dbg ("urb to unlink not found in chain");
+        return 0;
+}
+
+/* cancel all urbs which are in the chain.
+   this function must not be called from interrupt or completion handler.
+*/
+static void auerchain_unlink_all (pauerchain_t acp)
+{
+	unsigned long flags;
+        urb_t * urbp;
+        pauerchainelement_t acep;
+
+        dbg ("auerchain_unlink_all called");
+
+        /* clear the chain of waiting elements */
+        spin_lock_irqsave (&acp->lock, flags);
+        while (!list_empty (&acp->waiting_list)) {
+                /* get the next entry */
+                struct list_head *tmp = acp->waiting_list.next;
+                list_del (tmp);
+                acep = list_entry (tmp, auerchainelement_t, list);
+                urbp = acep->urbp;
+                urbp->context = acep->context;
+                urbp->complete = acep->complete;
+                list_add_tail (&acep->list, &acp->free_list);
+                spin_unlock_irqrestore (&acp->lock, flags);
+                dbg ("unlink waiting urb");
+                urbp->status = -ENOENT;
+                urbp->complete (urbp);
+                spin_lock_irqsave (&acp->lock, flags);
+        }
+        spin_unlock_irqrestore (&acp->lock, flags);
+
+        /* clear the active urb */
+        acep = acp->active;
+        if (acep) {
+                urbp = acep->urbp;
+                urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
+                dbg ("unlink active urb");
+                usb_unlink_urb (urbp);
+        }
+}
+
+
+/* free the chain.
+   this function must not be called from interrupt or completion handler.
+*/
+static void auerchain_free (pauerchain_t acp)
+{
+	unsigned long flags;
+        pauerchainelement_t acep;
+
+        dbg ("auerchain_free called");
+
+        /* first, cancel all pending urbs */
+        auerchain_unlink_all (acp);
+
+        /* free the elements */
+        spin_lock_irqsave (&acp->lock, flags);
+        while (!list_empty (&acp->free_list)) {
+                /* get the next entry */
+                struct list_head *tmp = acp->free_list.next;
+                list_del (tmp);
+                spin_unlock_irqrestore (&acp->lock, flags);
+		acep = list_entry (tmp, auerchainelement_t, list);
+                kfree (acep);
+	        spin_lock_irqsave (&acp->lock, flags);
+	}
+        spin_unlock_irqrestore (&acp->lock, flags);
+}
+
+
+/* Init the chain control structure */
+static void auerchain_init (pauerchain_t acp)
+{
+        /* init the chain data structure */
+        acp->active = NULL;
+	spin_lock_init (&acp->lock);
+        INIT_LIST_HEAD (&acp->waiting_list);
+        INIT_LIST_HEAD (&acp->free_list);
+}
+
+/* setup a chain.
+   It is assumed that there is no concurrency while setting up the chain
+   requirement: auerchain_init()
+*/
+static int auerchain_setup (pauerchain_t acp, unsigned int numElements)
+{
+        pauerchainelement_t acep;
+
+        dbg ("auerchain_setup called with %d elements", numElements);
+
+        /* fill the list of free elements */
+        for (;numElements; numElements--) {
+                acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL);
+                if (!acep) goto ac_fail;
+		memset (acep, 0, sizeof (auerchainelement_t));
+                INIT_LIST_HEAD (&acep->list);
+                list_add_tail (&acep->list, &acp->free_list);
+        }
+        return 0;
+
+ac_fail:/* free the elements */
+        while (!list_empty (&acp->free_list)) {
+                /* get the next entry */
+                struct list_head *tmp = acp->free_list.next;
+                list_del (tmp);
+                acep = list_entry (tmp, auerchainelement_t, list);
+                kfree (acep);
+        }
+        return -ENOMEM;
+}
+
+
+/* completion handler for synchronous chained URBs */
+static void auerchain_blocking_completion (urb_t *urb)
+{
+	pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
+	pchs->done = 1;
+	wmb();
+	wake_up (&pchs->wqh);
+}
+
+
+/* Starts chained urb and waits for completion or timeout */
+static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length)
+{
+	DECLARE_WAITQUEUE (wait, current);
+	auerchain_chs_t chs;
+	int status;
+
+	dbg ("auerchain_start_wait_urb called");
+	init_waitqueue_head (&chs.wqh);
+	chs.done = 0;
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	add_wait_queue (&chs.wqh, &wait);
+	urb->context = &chs;
+	status = auerchain_submit_urb (acp, urb);
+	if (status) {
+		/* something went wrong */
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&chs.wqh, &wait);
+		return status;
+	}
+
+	while (timeout && !chs.done)
+	{
+		timeout = schedule_timeout (timeout);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		rmb();
+	}
+
+	set_current_state (TASK_RUNNING);
+	remove_wait_queue (&chs.wqh, &wait);
+
+	if (!timeout && !chs.done) {
+		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
+			dbg ("auerchain_start_wait_urb: raced timeout");
+			status = urb->status;
+		} else {
+			dbg ("auerchain_start_wait_urb: timeout");
+			auerchain_unlink_urb (acp, urb);  /* remove urb safely */
+			status = -ETIMEDOUT;
+		}
+	} else
+		status = urb->status;
+
+	if (actual_length)
+		*actual_length = urb->actual_length;
+
+  	return status;
+}
+
+
+/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion
+   acp: pointer to the auerchain
+   dev: pointer to the usb device to send the message to
+   pipe: endpoint "pipe" to send the message to
+   request: USB message request value
+   requesttype: USB message request type value
+   value: USB message value
+   index: USB message index value
+   data: pointer to the data to send
+   size: length in bytes of the data to send
+   timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
+
+   This function sends a simple control message to a specified endpoint
+   and waits for the message to complete, or timeout.
+
+   If successful, it returns the transfered length, othwise a negative error number.
+
+   Don't use this function from within an interrupt context, like a
+   bottom half handler.  If you need a asyncronous message, or need to send
+   a message from within interrupt context, use auerchain_submit_urb()
+*/
+static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+			          __u16 value, __u16 index, void *data, __u16 size, int timeout)
+{
+	int ret;
+	devrequest *dr;
+	urb_t *urb;
+        int length;
+
+        dbg ("auerchain_control_msg");
+        dr = kmalloc (sizeof (devrequest), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+	urb = usb_alloc_urb (0);
+	if (!urb) {
+        	kfree (dr);
+		return -ENOMEM;
+        }
+
+	dr->requesttype = requesttype;
+	dr->request = request;
+	dr->value  = cpu_to_le16 (value);
+	dr->index  = cpu_to_le16 (index);
+	dr->length = cpu_to_le16 (size);
+
+	FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size,    /* build urb */
+		          (usb_complete_t)auerchain_blocking_completion,0);
+	ret = auerchain_start_wait_urb (acp, urb, timeout, &length);
+
+	usb_free_urb (urb);
+	kfree (dr);
+
+        if (ret < 0)
+		return ret;
+	else
+		return length;
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Buffer List helper functions                                      */
+
+/* free a single auerbuf */
+static void auerbuf_free (pauerbuf_t bp)
+{
+	if (bp->bufp) {
+		kfree (bp->bufp);
+	}
+	if (bp->dr) {
+		kfree (bp->dr);
+	}
+	if (bp->urbp) {
+		usb_free_urb (bp->urbp);
+	}
+	kfree (bp);
+}
+
+/* free the buffers from an auerbuf list */
+static void auerbuf_free_list (struct list_head *q)
+{
+        struct list_head *tmp;
+	struct list_head *p;
+	pauerbuf_t bp;
+
+	dbg ("auerbuf_free_list");
+	for (p = q->next; p != q;) {
+		bp = list_entry (p, auerbuf_t, buff_list);
+		tmp = p->next;
+		list_del (p);
+		p = tmp;
+		auerbuf_free (bp);
+	}
+}
+
+/* init the members of a list control block */
+static void auerbuf_init (pauerbufctl_t bcp)
+{
+	dbg ("auerbuf_init");
+	spin_lock_init (&bcp->lock);
+        INIT_LIST_HEAD (&bcp->free_buff_list);
+        INIT_LIST_HEAD (&bcp->rec_buff_list);
+}
+
+/* free all buffers from an auerbuf chain */
+static void auerbuf_free_buffers (pauerbufctl_t bcp)
+{
+	unsigned long flags;
+	dbg ("auerbuf_free_buffers");
+
+        spin_lock_irqsave (&bcp->lock, flags);
+
+	auerbuf_free_list (&bcp->free_buff_list);
+	auerbuf_free_list (&bcp->rec_buff_list);
+
+        spin_unlock_irqrestore (&bcp->lock, flags);
+}
+
+/* setup a list of buffers */
+/* requirement: auerbuf_init() */
+static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned int bufsize)
+{
+        pauerbuf_t bep;
+
+        dbg ("auerbuf_setup called with %d elements of %d bytes", numElements, bufsize);
+
+        /* fill the list of free elements */
+        for (;numElements; numElements--) {
+                bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL);
+                if (!bep) goto bl_fail;
+	        memset (bep, 0, sizeof (auerbuf_t));
+                bep->list = bcp;
+                INIT_LIST_HEAD (&bep->buff_list);
+                bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL);
+                if (!bep->bufp) goto bl_fail;
+                bep->dr = (devrequest *) kmalloc (sizeof (devrequest), GFP_KERNEL);
+                if (!bep->dr) goto bl_fail;
+                bep->urbp = usb_alloc_urb (0);
+                if (!bep->urbp) goto bl_fail;
+                list_add_tail (&bep->buff_list, &bcp->free_buff_list);
+        }
+        return 0;
+
+bl_fail:/* not enought memory. Free allocated elements */
+        dbg ("auerbuf_setup: no more memory");
+        auerbuf_free_buffers (bcp);
+        return -ENOMEM;
+}
+
+/* insert a used buffer into the free list */
+static void auerbuf_releasebuf( pauerbuf_t bp)
+{
+        unsigned long flags;
+        pauerbufctl_t bcp = bp->list;
+	bp->retries = 0;
+
+        dbg ("auerbuf_releasebuf called");
+        spin_lock_irqsave (&bcp->lock, flags);
+	list_add_tail (&bp->buff_list, &bcp->free_buff_list);
+        spin_unlock_irqrestore (&bcp->lock, flags);
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Completion handlers */
+
+/* Values of urb->status or results of usb_submit_urb():
+0		Initial, OK
+-EINPROGRESS	during submission until end
+-ENOENT		if urb is unlinked
+-ETIMEDOUT	Transfer timed out, NAK
+-ENOMEM		Memory Overflow
+-ENODEV		Specified USB-device or bus doesn't exist
+-ENXIO		URB already queued
+-EINVAL		a) Invalid transfer type specified (or not supported)
+		b) Invalid interrupt interval (0n256)
+-EAGAIN		a) Specified ISO start frame too early
+		b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again.
+-EFBIG		Too much ISO frames requested (currently uhci900)
+-EPIPE		Specified pipe-handle/Endpoint is already stalled
+-EMSGSIZE	Endpoint message size is zero, do interface/alternate setting
+-EPROTO		a) Bitstuff error
+		b) Unknown USB error
+-EILSEQ		CRC mismatch
+-ENOSR		Buffer error
+-EREMOTEIO	Short packet detected
+-EXDEV		ISO transfer only partially completed look at individual frame status for details
+-EINVAL		ISO madness, if this happens: Log off and go home
+-EOVERFLOW	babble
+*/
+
+/* check if a status code allows a retry */
+static int auerswald_status_retry (int status)
+{
+	switch (status) {
+	case 0:
+	case -ETIMEDOUT:
+	case -EOVERFLOW:
+	case -EAGAIN:
+	case -EPIPE:
+	case -EPROTO:
+	case -EILSEQ:
+	case -ENOSR:
+	case -EREMOTEIO:
+		return 1; /* do a retry */
+	}
+	return 0;	/* no retry possible */
+}
+
+/* Completion of asynchronous write block */
+static void auerchar_ctrlwrite_complete (urb_t * urb)
+{
+	pauerbuf_t bp = (pauerbuf_t) urb->context;
+	pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
+	dbg ("auerchar_ctrlwrite_complete called");
+
+	/* reuse the buffer */
+	auerbuf_releasebuf (bp);
+	/* Wake up all processes waiting for a buffer */
+	wake_up (&cp->bufferwait);
+}
+
+/* Completion handler for dummy retry packet */
+static void auerswald_ctrlread_wretcomplete (urb_t * urb)
+{
+        pauerbuf_t bp = (pauerbuf_t) urb->context;
+        pauerswald_t cp;
+	int ret;
+        dbg ("auerswald_ctrlread_wretcomplete called");
+        dbg ("complete with status: %d", urb->status);
+	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
+
+	/* check if it is possible to advance */
+	if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+		/* reuse the buffer */
+		err ("control dummy: transmission error %d, can not retry", urb->status);
+		auerbuf_releasebuf (bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up (&cp->bufferwait);
+		return;
+	}
+
+	/* fill the control message */
+	bp->dr->requesttype = AUT_RREQ;
+	bp->dr->request     = AUV_RBLOCK;
+	bp->dr->length      = bp->dr->value;	/* temporary stored */
+	bp->dr->value       = cpu_to_le16 (1);	/* Retry Flag */
+	/* bp->dr->index    = channel id;          remains */
+	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
+                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->length),
+		          (usb_complete_t)auerswald_ctrlread_complete,bp);
+
+	/* submit the control msg as next paket */
+	ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1);
+        if (ret) {
+        	dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+        	bp->urbp->status = ret;
+        	auerswald_ctrlread_complete (bp->urbp);
+    	}
+}
+
+/* completion handler for receiving of control messages */
+static void auerswald_ctrlread_complete (urb_t * urb)
+{
+        unsigned int  serviceid;
+        pauerswald_t  cp;
+        pauerscon_t   scp;
+        pauerbuf_t    bp  = (pauerbuf_t) urb->context;
+	int ret;
+        dbg ("auerswald_ctrlread_complete called");
+
+	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
+
+	/* check if there is valid data in this urb */
+        if (urb->status) {
+		dbg ("complete with non-zero status: %d", urb->status);
+		/* should we do a retry? */
+		if (!auerswald_status_retry (urb->status)
+		 || !cp->usbdev
+		 || (cp->version < AUV_RETRY)
+                 || (bp->retries >= AU_RETRIES)) {
+			/* reuse the buffer */
+			err ("control read: transmission error %d, can not retry", urb->status);
+			auerbuf_releasebuf (bp);
+			/* Wake up all processes waiting for a buffer */
+			wake_up (&cp->bufferwait);
+			return;
+		}
+		bp->retries++;
+		dbg ("Retry count = %d", bp->retries);
+		/* send a long dummy control-write-message to allow device firmware to react */
+		bp->dr->requesttype = AUT_WREQ;
+		bp->dr->request     = AUV_DUMMY;
+		bp->dr->value       = bp->dr->length; /* temporary storage */
+		// bp->dr->index    channel ID remains
+		bp->dr->length      = cpu_to_le16 (32); /* >= 8 bytes */
+		FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
+  			(unsigned char*)bp->dr, bp->bufp, 32,
+	   		(usb_complete_t)auerswald_ctrlread_wretcomplete,bp);
+
+		/* submit the control msg as next paket */
+       		ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1);
+       		if (ret) {
+               		dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+               		bp->urbp->status = ret;
+               		auerswald_ctrlread_wretcomplete (bp->urbp);
+		}
+                return;
+        }
+
+        /* get the actual bytecount (incl. headerbyte) */
+        bp->len = urb->actual_length;
+        serviceid = bp->bufp[0] & AUH_TYPEMASK;
+        dbg ("Paket with serviceid %d and %d bytes received", serviceid, bp->len);
+
+        /* dispatch the paket */
+        scp = cp->services[serviceid];
+        if (scp) {
+                /* look, Ma, a listener! */
+                scp->dispatch (scp, bp);
+        }
+
+        /* release the paket */
+        auerbuf_releasebuf (bp);
+	/* Wake up all processes waiting for a buffer */
+	wake_up (&cp->bufferwait);
+}
+
+/*-------------------------------------------------------------------*/
+/* Handling of Interrupt Endpoint                                    */
+/* This interrupt Endpoint is used to inform the host about waiting
+   messages from the USB device.
+*/
+/* int completion handler. */
+static void auerswald_int_complete (urb_t * urb)
+{
+        unsigned long flags;
+        unsigned  int channelid;
+        unsigned  int bytecount;
+        int ret;
+        pauerbuf_t   bp = NULL;
+        pauerswald_t cp = (pauerswald_t) urb->context;
+
+        dbg ("auerswald_int_complete called");
+
+        /* do not respond to an error condition */
+        if (urb->status != 0) {
+                dbg ("nonzero URB status = %d", urb->status);
+                return;
+        }
+
+        /* check if all needed data was received */
+	if (urb->actual_length < AU_IRQMINSIZE) {
+                dbg ("invalid data length received: %d bytes", urb->actual_length);
+                return;
+        }
+
+        /* check the command code */
+        if (cp->intbufp[0] != AU_IRQCMDID) {
+                dbg ("invalid command received: %d", cp->intbufp[0]);
+                return;
+        }
+
+        /* check the command type */
+        if (cp->intbufp[1] != AU_BLOCKRDY) {
+                dbg ("invalid command type received: %d", cp->intbufp[1]);
+                return;
+        }
+
+        /* now extract the information */
+        channelid = cp->intbufp[2];
+        bytecount = le16_to_cpup (&cp->intbufp[3]);
+
+        /* check the channel id */
+        if (channelid >= AUH_TYPESIZE) {
+                dbg ("invalid channel id received: %d", channelid);
+                return;
+        }
+
+        /* check the byte count */
+        if (bytecount > (cp->maxControlLength+AUH_SIZE)) {
+                dbg ("invalid byte count received: %d", bytecount);
+                return;
+        }
+        dbg ("Service Channel = %d", channelid);
+        dbg ("Byte Count = %d", bytecount);
+
+        /* get a buffer for the next data paket */
+        spin_lock_irqsave (&cp->bufctl.lock, flags);
+        if (!list_empty (&cp->bufctl.free_buff_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = cp->bufctl.free_buff_list.next;
+                list_del (tmp);
+                bp = list_entry (tmp, auerbuf_t, buff_list);
+        }
+        spin_unlock_irqrestore (&cp->bufctl.lock, flags);
+
+        /* if no buffer available: skip it */
+        if (!bp) {
+                dbg ("auerswald_int_complete: no data buffer available");
+                /* can we do something more?
+		   This is a big problem: if this int packet is ignored, the
+		   device will wait forever and not signal any more data.
+		   The only real solution is: having enought buffers!
+		   Or perhaps temporary disabling the int endpoint?
+		*/
+		return;
+        }
+
+	/* fill the control message */
+        bp->dr->requesttype = AUT_RREQ;
+	bp->dr->request     = AUV_RBLOCK;
+	bp->dr->value       = cpu_to_le16 (0);
+	bp->dr->index       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->length      = cpu_to_le16 (bytecount);
+	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
+                          (unsigned char*)bp->dr, bp->bufp, bytecount,
+		          (usb_complete_t)auerswald_ctrlread_complete,bp);
+
+        /* submit the control msg */
+        ret = auerchain_submit_urb (&cp->controlchain, bp->urbp);
+        if (ret) {
+                dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);
+                bp->urbp->status = ret;
+                auerswald_ctrlread_complete( bp->urbp);
+		/* here applies the same problem as above: device locking! */
+        }
+}
+
+/* int memory deallocation
+   NOTE: no mutex please!
+*/
+static void auerswald_int_free (pauerswald_t cp)
+{
+        if (cp->inturbp) {
+                usb_free_urb (cp->inturbp);
+                cp->inturbp = NULL;
+        }
+        if (cp->intbufp) {
+                kfree (cp->intbufp);
+                cp->intbufp = NULL;
+        }
+}
+
+/* This function is called to activate the interrupt
+   endpoint. This function returns 0 if successfull or an error code.
+   NOTE: no mutex please!
+*/
+static int auerswald_int_open (pauerswald_t cp)
+{
+        int ret;
+	struct usb_endpoint_descriptor *ep;
+	int irqsize;
+	dbg ("auerswald_int_open");
+
+	ep = usb_epnum_to_ep_desc (cp->usbdev, USB_DIR_IN | AU_IRQENDP);
+	if (!ep) {
+		ret = -EFAULT;
+  		goto intoend;
+    	}
+	irqsize = ep->wMaxPacketSize;
+	cp->irqsize = irqsize;
+
+	/* allocate the urb and data buffer */
+        if (!cp->inturbp) {
+                cp->inturbp = usb_alloc_urb (0);
+                if (!cp->inturbp) {
+                        ret = -ENOMEM;
+                        goto intoend;
+                }
+        }
+        if (!cp->intbufp) {
+                cp->intbufp = (char *) kmalloc (irqsize, GFP_KERNEL);
+                if (!cp->intbufp) {
+                        ret = -ENOMEM;
+                        goto intoend;
+                }
+        }
+        /* setup urb */
+        FILL_INT_URB (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->bInterval);
+        /* start the urb */
+	cp->inturbp->status = 0;	/* needed! */
+	ret = usb_submit_urb (cp->inturbp);
+
+intoend:
+        if (ret < 0) {
+                /* activation of interrupt endpoint has failed. Now clean up. */
+                dbg ("auerswald_int_open: activation of int endpoint failed");
+
+                /* deallocate memory */
+                auerswald_int_free (cp);
+        }
+        return ret;
+}
+
+/* This function is called to deactivate the interrupt
+   endpoint. This function returns 0 if successfull or an error code.
+   NOTE: no mutex please!
+*/
+static int auerswald_int_release (pauerswald_t cp)
+{
+        int ret = 0;
+        dbg ("auerswald_int_release");
+
+        /* stop the int endpoint */
+        if (cp->inturbp) {
+                ret = usb_unlink_urb (cp->inturbp);
+                if (ret)
+	                dbg ("nonzero int unlink result received: %d", ret);
+        }
+
+        /* deallocate memory */
+        auerswald_int_free (cp);
+
+        return ret;
+}
+
+/* --------------------------------------------------------------------- */
+/* Helper functions                                                      */
+
+/* wake up waiting readers */
+static void auerchar_disconnect (pauerscon_t scp)
+{
+        pauerchar_t ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext)));
+	dbg ("auerchar_disconnect called");
+	ccp->removed = 1;
+	wake_up (&ccp->readwait);
+}
+
+
+/* dispatch a read paket to a waiting character device */
+static void auerchar_ctrlread_dispatch (pauerscon_t scp, pauerbuf_t bp)
+{
+	unsigned long flags;
+        pauerchar_t ccp;
+        pauerbuf_t newbp = NULL;
+        char * charp;
+        dbg ("auerchar_ctrlread_dispatch called");
+        ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext)));
+
+        /* get a read buffer from character device context */
+        spin_lock_irqsave (&ccp->bufctl.lock, flags);
+        if (!list_empty (&ccp->bufctl.free_buff_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = ccp->bufctl.free_buff_list.next;
+                list_del (tmp);
+                newbp = list_entry (tmp, auerbuf_t, buff_list);
+        }
+        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
+
+        if (!newbp) {
+                dbg ("No read buffer available, discard paket!");
+                return;     /* no buffer, no dispatch */
+        }
+
+        /* copy information to new buffer element
+           (all buffers have the same length) */
+        charp = newbp->bufp;
+        newbp->bufp = bp->bufp;
+        bp->bufp = charp;
+        newbp->len = bp->len;
+
+        /* insert new buffer in read list */
+        spin_lock_irqsave (&ccp->bufctl.lock, flags);
+	list_add_tail (&newbp->buff_list, &ccp->bufctl.rec_buff_list);
+        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
+        dbg ("read buffer appended to rec_list");
+
+        /* wake up pending synchronous reads */
+	wake_up (&ccp->readwait);
+}
+
+
+/* Delete an auerswald driver context */
+static void auerswald_delete( pauerswald_t cp)
+{
+	dbg( "auerswald_delete");
+	if (cp == NULL) return;
+
+	/* Wake up all processes waiting for a buffer */
+	wake_up (&cp->bufferwait);
+
+	/* Cleaning up */
+	auerswald_int_release (cp);
+	auerchain_free (&cp->controlchain);
+	auerbuf_free_buffers (&cp->bufctl);
+
+	/* release the memory */
+	kfree( cp);
+}
+
+
+/* Delete an auerswald character context */
+static void auerchar_delete( pauerchar_t ccp)
+{
+	dbg ("auerchar_delete");
+	if (ccp == NULL) return;
+
+        /* wake up pending synchronous reads */
+	ccp->removed = 1;
+	wake_up (&ccp->readwait);
+
+	/* remove the read buffer */
+	if (ccp->readbuf) {
+		auerbuf_releasebuf (ccp->readbuf);
+		ccp->readbuf = NULL;
+	}
+
+	/* remove the character buffers */
+	auerbuf_free_buffers (&ccp->bufctl);
+
+	/* release the memory */
+	kfree( ccp);
+}
+
+
+/* add a new service to the device
+   scp->id must be set!
+   return: 0 if OK, else error code
+*/
+static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp)
+{
+	int ret;
+
+	/* is the device available? */
+	if (!cp->usbdev) {
+		dbg ("usbdev == NULL");
+		return -EIO;	/*no: can not add a service, sorry*/
+	}
+
+	/* is the service available? */
+	if (cp->services[scp->id]) {
+		dbg ("service is busy");
+                return -EBUSY;
+	}
+
+	/* device is available, service is free */
+	cp->services[scp->id] = scp;
+
+	/* register service in device */
+	ret = auerchain_control_msg(
+		&cp->controlchain,                      /* pointer to control chain */
+		cp->usbdev,                             /* pointer to device */
+		usb_sndctrlpipe (cp->usbdev, 0),        /* pipe to control endpoint */
+		AUV_CHANNELCTL,                         /* USB message request value */
+		AUT_WREQ,                               /* USB message request type value */
+		0x01,              /* open                 USB message value */
+		scp->id,            		        /* USB message index value */
+		NULL,                                   /* pointer to the data to send */
+		0,                                      /* length in bytes of the data to send */
+		HZ * 2);                                /* time to wait for the message to complete before timing out */
+	if (ret < 0) {
+		dbg ("auerswald_addservice: auerchain_control_msg returned error code %d", ret);
+		/* undo above actions */
+		cp->services[scp->id] = NULL;
+		return ret;
+	}
+
+	dbg ("auerswald_addservice: channel open OK");
+	return 0;
+}
+
+
+/* remove a service from the the device
+   scp->id must be set! */
+static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
+{
+	dbg ("auerswald_removeservice called");
+
+	/* check if we have a service allocated */
+	if (scp->id == AUH_UNASSIGNED) return;
+
+	/* If there is a device: close the channel */
+	if (cp->usbdev) {
+		/* Close the service channel inside the device */
+		int ret = auerchain_control_msg(
+		&cp->controlchain,            		/* pointer to control chain */
+		cp->usbdev,         		        /* pointer to device */
+		usb_sndctrlpipe (cp->usbdev, 0),	/* pipe to control endpoint */
+		AUV_CHANNELCTL,                         /* USB message request value */
+		AUT_WREQ,                               /* USB message request type value */
+		0x00,              // close             /* USB message value */
+		scp->id,            		        /* USB message index value */
+		NULL,                                   /* pointer to the data to send */
+		0,                                      /* length in bytes of the data to send */
+		HZ * 2);                                /* time to wait for the message to complete before timing out */
+		if (ret < 0) {
+			dbg ("auerswald_removeservice: auerchain_control_msg returned error code %d", ret);
+		}
+		else {
+			dbg ("auerswald_removeservice: channel close OK");
+		}
+	}
+
+	/* remove the service from the device */
+	cp->services[scp->id] = NULL;
+	scp->id = AUH_UNASSIGNED;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Char device functions                                                 */
+
+/* Open a new character device */
+static int auerchar_open (struct inode *inode, struct file *file)
+{
+	int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE;
+	pauerswald_t cp = NULL;
+	pauerchar_t ccp = NULL;
+        int ret;
+
+        /* minor number in range? */
+	if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
+		return -ENODEV;
+        }
+	/* usb device available? */
+	if (down_interruptible (&dev_table_mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = dev_table[dtindex];
+	if (cp == NULL) {
+		up (&dev_table_mutex);
+		return -ENODEV;
+	}
+	if (down_interruptible (&cp->mutex)) {
+		up (&dev_table_mutex);
+		return -ERESTARTSYS;
+	}
+	up (&dev_table_mutex);
+
+	/* we have access to the device. Now lets allocate memory */
+	ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
+	if (ccp == NULL) {
+		err ("out of memory");
+		ret = -ENOMEM;
+		goto ofail;
+	}
+
+	/* Initialize device descriptor */
+	memset( ccp, 0, sizeof(auerchar_t));
+	init_MUTEX( &ccp->mutex);
+	init_MUTEX( &ccp->readmutex);
+        auerbuf_init (&ccp->bufctl);
+        ccp->scontext.id = AUH_UNASSIGNED;
+        ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
+	ccp->scontext.disconnect = auerchar_disconnect;
+	init_waitqueue_head (&ccp->readwait);
+
+	ret = auerbuf_setup (&ccp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE);
+       	if (ret) {
+		goto ofail;
+	}
+
+	cp->open_count++;
+	ccp->auerdev = cp;
+	dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name);
+	up (&cp->mutex);
+
+	/* file IO stuff */
+	file->f_pos = 0;
+	file->private_data = ccp;
+	return 0;
+
+	/* Error exit */
+ofail:	up (&cp->mutex);
+	auerchar_delete (ccp);
+	return ret;
+}
+
+
+/* IOCTL functions */
+static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	pauerchar_t ccp = (pauerchar_t) file->private_data;
+	int ret = 0;
+        audevinfo_t devinfo;
+        pauerswald_t cp = NULL;
+	unsigned int u;
+        dbg ("ioctl");
+
+	/* get the mutexes */
+	if (down_interruptible (&ccp->mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = ccp->auerdev;
+	if (!cp) {
+		up (&ccp->mutex);
+                return -ENODEV;
+	}
+	if (down_interruptible (&cp->mutex)) {
+		up(&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+
+	/* Check for removal */
+	if (!cp->usbdev) {
+		up(&cp->mutex);
+		up(&ccp->mutex);
+                return -ENODEV;
+	}
+
+	switch (cmd) {
+
+	/* return != 0 if Transmitt channel ready to send */
+	case IOCTL_AU_TXREADY:
+		dbg ("IOCTL_AU_TXREADY");
+		u   = ccp->auerdev
+		   && (ccp->scontext.id != AUH_UNASSIGNED)
+		   && !list_empty (&cp->bufctl.free_buff_list);
+	        ret = put_user (u, (unsigned int *) arg);
+		break;
+
+	/* return != 0 if connected to a service channel */
+	case IOCTL_AU_CONNECT:
+		dbg ("IOCTL_AU_CONNECT");
+		u = (ccp->scontext.id != AUH_UNASSIGNED);
+	        ret = put_user (u, (unsigned int *) arg);
+		break;
+
+	/* return != 0 if Receive Data available */
+	case IOCTL_AU_RXAVAIL:
+		dbg ("IOCTL_AU_RXAVAIL");
+		if (ccp->scontext.id == AUH_UNASSIGNED) {
+                        ret = -EIO;
+                        break;
+                }
+		u = 0;	/* no data */
+		if (ccp->readbuf) {
+			int restlen = ccp->readbuf->len - ccp->readoffset;
+			if (restlen > 0) u = 1;
+		}
+		if (!u) {
+        		if (!list_empty (&ccp->bufctl.rec_buff_list)) {
+				u = 1;
+			}
+		}
+	        ret = put_user (u, (unsigned int *) arg);
+		break;
+
+	/* return the max. buffer length for the device */
+	case IOCTL_AU_BUFLEN:
+		dbg ("IOCTL_AU_BUFLEN");
+		u = cp->maxControlLength;
+	        ret = put_user (u, (unsigned int *) arg);
+		break;
+
+	/* requesting a service channel */
+        case IOCTL_AU_SERVREQ:
+		dbg ("IOCTL_AU_SERVREQ");
+                /* requesting a service means: release the previous one first */
+		auerswald_removeservice (cp, &ccp->scontext);
+		/* get the channel number */
+		ret = get_user (u, (unsigned int *) arg);
+		if (ret) {
+			break;
+		}
+		if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) {
+                        ret = -EIO;
+                        break;
+                }
+                dbg ("auerchar service request parameters are ok");
+		ccp->scontext.id = u;
+
+		/* request the service now */
+		ret = auerswald_addservice (cp, &ccp->scontext);
+		if (ret) {
+			/* no: revert service entry */
+                	ccp->scontext.id = AUH_UNASSIGNED;
+		}
+		break;
+
+	/* get a string descriptor for the device */
+	case IOCTL_AU_DEVINFO:
+		dbg ("IOCTL_AU_DEVINFO");
+                if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) {
+        		ret = -EFAULT;
+	        	break;
+                }
+		u = strlen(cp->dev_desc)+1;
+		if (u > devinfo.bsize) {
+			u = devinfo.bsize;
+		}
+		ret = copy_to_user(devinfo.buf, cp->dev_desc, u);
+		break;
+
+	/* get the max. string descriptor length */
+        case IOCTL_AU_SLEN:
+		dbg ("IOCTL_AU_SLEN");
+		u = AUSI_DLEN;
+	        ret = put_user (u, (unsigned int *) arg);
+		break;
+
+	default:
+		dbg ("IOCTL_AU_UNKNOWN");
+		ret = -ENOIOCTLCMD;
+		break;
+        }
+	/* release the mutexes */
+	up(&cp->mutex);
+	up(&ccp->mutex);
+	return ret;
+}
+
+
+/* Seek is not supported */
+static loff_t auerchar_llseek (struct file *file, loff_t offset, int origin)
+{
+        dbg ("auerchar_seek");
+        return -ESPIPE;
+}
+
+
+/* Read data from the device */
+static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+        unsigned long flags;
+	pauerchar_t ccp = (pauerchar_t) file->private_data;
+        pauerbuf_t   bp = NULL;
+	wait_queue_t wait;
+
+        dbg ("auerchar_read");
+
+	/* Error checking */
+	if (!ccp)
+		return -EIO;
+	if (*ppos)
+ 		return -ESPIPE;
+        if (count == 0)
+		return 0;
+
+	/* get the mutex */
+	if (down_interruptible (&ccp->mutex))
+		return -ERESTARTSYS;
+
+	/* Can we expect to read something? */
+	if (ccp->scontext.id == AUH_UNASSIGNED) {
+		up (&ccp->mutex);
+                return -EIO;
+	}
+
+	/* only one reader per device allowed */
+	if (down_interruptible (&ccp->readmutex)) {
+		up (&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+
+	/* read data from readbuf, if available */
+doreadbuf:
+	bp = ccp->readbuf;
+	if (bp) {
+		/* read the maximum bytes */
+		int restlen = bp->len - ccp->readoffset;
+		if (restlen < 0)
+			restlen = 0;
+		if (count > restlen)
+			count = restlen;
+		if (count) {
+			if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) {
+				dbg ("auerswald_read: copy_to_user failed");
+				up (&ccp->readmutex);
+				up (&ccp->mutex);
+				return -EFAULT;
+			}
+		}
+		/* advance the read offset */
+		ccp->readoffset += count;
+		restlen -= count;
+		// reuse the read buffer
+		if (restlen <= 0) {
+			auerbuf_releasebuf (bp);
+			ccp->readbuf = NULL;
+		}
+		/* return with number of bytes read */
+		if (count) {
+			up (&ccp->readmutex);
+			up (&ccp->mutex);
+			return count;
+		}
+	}
+
+	/* a read buffer is not available. Try to get the next data block. */
+doreadlist:
+	/* Preparing for sleep */
+	init_waitqueue_entry (&wait, current);
+	set_current_state (TASK_INTERRUPTIBLE);
+	add_wait_queue (&ccp->readwait, &wait);
+
+	bp = NULL;
+	spin_lock_irqsave (&ccp->bufctl.lock, flags);
+        if (!list_empty (&ccp->bufctl.rec_buff_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = ccp->bufctl.rec_buff_list.next;
+                list_del (tmp);
+                bp = list_entry (tmp, auerbuf_t, buff_list);
+        }
+        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
+
+	/* have we got data? */
+	if (bp) {
+		ccp->readbuf = bp;
+		ccp->readoffset = AUH_SIZE; /* for headerbyte */
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&ccp->readwait, &wait);
+		goto doreadbuf;		  /* now we can read! */
+	}
+
+	/* no data available. Should we wait? */
+	if (file->f_flags & O_NONBLOCK) {
+                dbg ("No read buffer available, returning -EAGAIN");
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&ccp->readwait, &wait);
+		up (&ccp->readmutex);
+		up (&ccp->mutex);
+		return -EAGAIN;  /* nonblocking, no data available */
+        }
+
+	/* yes, we should wait! */
+	up (&ccp->mutex); /* allow other operations while we wait */
+	schedule();
+	remove_wait_queue (&ccp->readwait, &wait);
+	if (signal_pending (current)) {
+		/* waked up by a signal */
+		up (&ccp->readmutex);
+		return -ERESTARTSYS;
+	}
+
+	/* Anything left to read? */
+	if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
+		up (&ccp->readmutex);
+		return -EIO;
+	}
+
+	if (down_interruptible (&ccp->mutex)) {
+		up (&ccp->readmutex);
+		return -ERESTARTSYS;
+	}
+
+	/* try to read the incomming data again */
+	goto doreadlist;
+}
+
+
+/* Write a data block into the right service channel of the device */
+static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos)
+{
+	pauerchar_t ccp = (pauerchar_t) file->private_data;
+        pauerswald_t cp = NULL;
+        pauerbuf_t bp;
+        unsigned long flags;
+	int ret;
+	wait_queue_t wait;
+
+        dbg ("auerchar_write %d bytes", len);
+
+	/* Error checking */
+	if (!ccp)
+		return -EIO;
+        if (*ppos)
+		return -ESPIPE;
+        if (len == 0)
+                return 0;
+
+write_again:
+	/* get the mutex */
+	if (down_interruptible (&ccp->mutex))
+		return -ERESTARTSYS;
+
+	/* Can we expect to write something? */
+	if (ccp->scontext.id == AUH_UNASSIGNED) {
+		up (&ccp->mutex);
+                return -EIO;
+	}
+
+	cp = ccp->auerdev;
+	if (!cp) {
+		up (&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+	if (down_interruptible (&cp->mutex)) {
+		up (&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+	if (!cp->usbdev) {
+		up (&cp->mutex);
+		up (&ccp->mutex);
+		return -EIO;
+	}
+	/* Prepare for sleep */
+	init_waitqueue_entry (&wait, current);
+	set_current_state (TASK_INTERRUPTIBLE);
+	add_wait_queue (&cp->bufferwait, &wait);
+
+	/* Try to get a buffer from the device pool.
+	   We can't use a buffer from ccp->bufctl because the write
+	   command will last beond a release() */
+	bp = NULL;
+	spin_lock_irqsave (&cp->bufctl.lock, flags);
+        if (!list_empty (&cp->bufctl.free_buff_list)) {
+                /* yes: get the entry */
+                struct list_head *tmp = cp->bufctl.free_buff_list.next;
+                list_del (tmp);
+                bp = list_entry (tmp, auerbuf_t, buff_list);
+        }
+        spin_unlock_irqrestore (&cp->bufctl.lock, flags);
+
+	/* are there any buffers left? */
+	if (!bp) {
+		up (&cp->mutex);
+		up (&ccp->mutex);
+
+		/* NONBLOCK: don't wait */
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state (TASK_RUNNING);
+			remove_wait_queue (&cp->bufferwait, &wait);
+			return -EAGAIN;
+		}
+
+		/* BLOCKING: wait */
+		schedule();
+		remove_wait_queue (&cp->bufferwait, &wait);
+		if (signal_pending (current)) {
+			/* waked up by a signal */
+			return -ERESTARTSYS;
+		}
+		goto write_again;
+	} else {
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&cp->bufferwait, &wait);
+	}
+
+	/* protect against too big write requests */
+	if (len > cp->maxControlLength) len = cp->maxControlLength;
+
+	/* Fill the buffer */
+	if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) {
+		dbg ("copy_from_user failed");
+		auerbuf_releasebuf (bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up (&cp->bufferwait);
+		up (&cp->mutex);
+		up (&ccp->mutex);
+		return -EIO;
+	}
+
+	/* set the header byte */
+        *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT;
+
+	/* Set the transfer Parameters */
+	bp->len = len+AUH_SIZE;
+        bp->dr->requesttype = AUT_WREQ;
+	bp->dr->request     = AUV_WBLOCK;
+	bp->dr->value       = cpu_to_le16 (0);
+	bp->dr->index       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->length      = cpu_to_le16 (len+AUH_SIZE);
+	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
+                   (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE,
+		    auerchar_ctrlwrite_complete, bp);
+	/* up we go */
+	ret = auerchain_submit_urb (&cp->controlchain, bp->urbp);
+	up (&cp->mutex);
+	if (ret) {
+		dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
+		auerbuf_releasebuf (bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up (&cp->bufferwait);
+		up (&ccp->mutex);
+		return -EIO;
+	}
+	else {
+		dbg ("auerchar_write: Write OK");
+		up (&ccp->mutex);
+		return len;
+	}
+}
+
+
+/* Close a character device */
+static int auerchar_release (struct inode *inode, struct file *file)
+{
+	pauerchar_t ccp = (pauerchar_t) file->private_data;
+	pauerswald_t cp;
+	dbg("release");
+
+	/* get the mutexes */
+	if (down_interruptible (&ccp->mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = ccp->auerdev;
+	if (cp) {
+		if (down_interruptible (&cp->mutex)) {
+			up (&ccp->mutex);
+			return -ERESTARTSYS;
+		}
+		/* remove an open service */
+		auerswald_removeservice (cp, &ccp->scontext);
+		/* detach from device */
+		if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
+			/* usb device waits for removal */
+			up (&cp->mutex);
+			auerswald_delete (cp);
+		} else {
+			up (&cp->mutex);
+		}
+		cp = NULL;
+		ccp->auerdev = NULL;
+	}
+	up (&ccp->mutex);
+	auerchar_delete (ccp);
+
+	return 0;
+}
+
+
+/*----------------------------------------------------------------------*/
+/* File operation structure                                             */
+static struct file_operations auerswald_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		auerchar_llseek,
+	read:		auerchar_read,
+	write:          auerchar_write,
+	ioctl:		auerchar_ioctl,
+	open:		auerchar_open,
+	release:	auerchar_release,
+};
+
+
+/* --------------------------------------------------------------------- */
+/* Special USB driver functions                                          */
+
+/* Probe if this driver wants to serve an USB device
+
+   This entry point is called whenever a new device is attached to the bus.
+   Then the device driver has to create a new instance of its internal data
+   structures for the new device.
+
+   The  dev argument specifies the device context, which contains pointers
+   to all USB descriptors. The  interface argument specifies the interface
+   number. If a USB driver wants to bind itself to a particular device and
+   interface it has to return a pointer. This pointer normally references
+   the device driver's context structure.
+
+   Probing normally is done by checking the vendor and product identifications
+   or the class and subclass definitions. If they match the interface number
+   is compared with the ones supported by the driver. When probing is done
+   class based it might be necessary to parse some more USB descriptors because
+   the device properties can differ in a wide range.
+*/
+static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum,
+			      const struct usb_device_id *id)
+{
+	pauerswald_t cp = NULL;
+	DECLARE_WAIT_QUEUE_HEAD (wqh);
+	unsigned int dtindex;
+	unsigned int u = 0;
+	char *pbuf;
+	int ret;
+
+	dbg ("probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+	     usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
+
+	/* See if the device offered us matches that we can accept */
+	if (usbdev->descriptor.idVendor != ID_AUERSWALD) return NULL;
+
+        /* we use only the first -and only- interface */
+        if (ifnum != 0) return NULL;
+
+	/* prevent module unloading while sleeping */
+	MOD_INC_USE_COUNT;
+
+	/* allocate memory for our device and intialize it */
+	cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL);
+	if (cp == NULL) {
+		err ("out of memory");
+		goto pfail;
+	}
+
+	/* Initialize device descriptor */
+	memset (cp, 0, sizeof(auerswald_t));
+	init_MUTEX (&cp->mutex);
+	cp->usbdev = usbdev;
+	auerchain_init (&cp->controlchain);
+        auerbuf_init (&cp->bufctl);
+	init_waitqueue_head (&cp->bufferwait);
+
+	/* find a free slot in the device table */
+	down (&dev_table_mutex);
+	for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
+		if (dev_table[dtindex] == NULL)
+			break;
+	}
+	if ( dtindex >= AUER_MAX_DEVICES) {
+		err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
+		up (&dev_table_mutex);
+		goto pfail;
+	}
+
+	/* Give the device a name */
+	sprintf (cp->name, AU_PREFIX "%d", dtindex);
+
+	/* Store the index */
+	cp->dtindex = dtindex;
+	dev_table[dtindex] = cp;
+	up (&dev_table_mutex);
+
+	/* initialize the devfs node for this device and register it */
+	cp->devfs = devfs_register (usb_devfs_handle, cp->name,
+				    DEVFS_FL_DEFAULT, USB_MAJOR,
+				    AUER_MINOR_BASE + dtindex,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &auerswald_fops, NULL);
+
+	/* Get the usb version of the device */
+	cp->version = cp->usbdev->descriptor.bcdDevice;
+	dbg ("Version is %X", cp->version);
+
+	/* allow some time to settle the device */
+	sleep_on_timeout (&wqh, HZ / 3 );
+
+	/* Try to get a suitable textual description of the device */
+	/* Device name:*/
+	ret = usb_string( cp->usbdev, AUSI_DEVICE, cp->dev_desc, AUSI_DLEN-1);
+	if (ret >= 0) {
+		u += ret;
+		/* Append Serial Number */
+		memcpy(&cp->dev_desc[u], ",Ser# ", 6);
+		u += 6;
+		ret = usb_string( cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u], AUSI_DLEN-u-1);
+		if (ret >= 0) {
+			u += ret;
+			/* Append subscriber number */
+			memcpy(&cp->dev_desc[u], ", ", 2);
+			u += 2;
+			ret = usb_string( cp->usbdev, AUSI_MSN, &cp->dev_desc[u], AUSI_DLEN-u-1);
+			if (ret >= 0) {
+				u += ret;
+			}
+		}
+	}
+	cp->dev_desc[u] = '\0';
+	info("device is a %s", cp->dev_desc);
+
+        /* get the maximum allowed control transfer length */
+        pbuf = (char *) kmalloc (2, GFP_KERNEL);    /* use an allocated buffer because of urb target */
+        if (!pbuf) {
+		err( "out of memory");
+		goto pfail;
+	}
+        ret = usb_control_msg(cp->usbdev,           /* pointer to device */
+                usb_rcvctrlpipe( cp->usbdev, 0 ),   /* pipe to control endpoint */
+                AUV_GETINFO,                        /* USB message request value */
+                AUT_RREQ,                           /* USB message request type value */
+                0,                                  /* USB message value */
+                AUDI_MBCTRANS,                      /* USB message index value */
+                pbuf,                               /* pointer to the receive buffer */
+                2,                                  /* length of the buffer */
+                HZ * 2);                            /* time to wait for the message to complete before timing out */
+        if (ret == 2) {
+	        cp->maxControlLength = le16_to_cpup(pbuf);
+                kfree(pbuf);
+                dbg("setup: max. allowed control transfersize is %d bytes", cp->maxControlLength);
+        } else {
+                kfree(pbuf);
+                err("setup: getting max. allowed control transfer length failed with error %d", ret);
+		goto pfail;
+        }
+
+	/* allocate a chain for the control messages */
+        if (auerchain_setup (&cp->controlchain, AUCH_ELEMENTS)) {
+		err ("out of memory");
+		goto pfail;
+	}
+
+        /* allocate buffers for control messages */
+	if (auerbuf_setup (&cp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE)) {
+		err ("out of memory");
+		goto pfail;
+	}
+
+	/* start the interrupt endpoint */
+	if (auerswald_int_open (cp)) {
+		err ("int endpoint failed");
+		goto pfail;
+	}
+
+	/* all OK */
+	return cp;
+
+	/* Error exit: clean up the memory */
+pfail:	auerswald_delete (cp);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+/* Disconnect driver from a served device
+
+   This function is called whenever a device which was served by this driver
+   is disconnected.
+
+   The argument  dev specifies the device context and the  driver_context
+   returns a pointer to the previously registered  driver_context of the
+   probe function. After returning from the disconnect function the USB
+   framework completly deallocates all data structures associated with
+   this device. So especially the usb_device structure must not be used
+   any longer by the usb driver.
+*/
+static void auerswald_disconnect (struct usb_device *usbdev, void *driver_context)
+{
+	pauerswald_t cp = (pauerswald_t) driver_context;
+	unsigned int u;
+
+	down (&cp->mutex);
+	info ("device /dev/usb/%s now disconnecting", cp->name);
+
+	/* remove from device table */
+	/* Nobody can open() this device any more */
+	down (&dev_table_mutex);
+	dev_table[cp->dtindex] = NULL;
+	up (&dev_table_mutex);
+
+	/* remove our devfs node */
+	/* Nobody can see this device any more */
+	devfs_unregister (cp->devfs);
+
+	/* Stop the interrupt endpoint */
+	auerswald_int_release (cp);
+
+	/* remove the control chain allocated in auerswald_probe
+	   This has the benefit of
+	   a) all pending (a)synchronous urbs are unlinked
+	   b) all buffers dealing with urbs are reclaimed
+	*/
+	auerchain_free (&cp->controlchain);
+
+	if (cp->open_count == 0) {
+		/* nobody is using this device. So we can clean up now */
+		up (&cp->mutex);/* up() is possible here because no other task
+				   can open the device (see above). I don't want
+				   to kfree() a locked mutex. */
+		auerswald_delete (cp);
+	} else {
+		/* device is used. Remove the pointer to the
+		   usb device (it's not valid any more). The last
+		   release() will do the clean up */
+		cp->usbdev = NULL;
+		up (&cp->mutex);
+		/* Terminate waiting writers */
+		wake_up (&cp->bufferwait);
+		/* Inform all waiting readers */
+		for ( u = 0; u < AUH_TYPESIZE; u++) {
+			pauerscon_t scp = cp->services[u];
+			if (scp) scp->disconnect( scp);
+		}
+	}
+
+	/* The device releases this module */
+	MOD_DEC_USE_COUNT;
+}
+
+/* Descriptor for the devices which are served by this driver.
+   NOTE: this struct is parsed by the usbmanager install scripts.
+         Don't change without caution!
+*/
+static struct usb_device_id auerswald_ids [] = {
+	{ USB_DEVICE (ID_AUERSWALD, 0x00C0) },          /* COMpact 2104 USB */
+	{ USB_DEVICE (ID_AUERSWALD, 0x00DB) },          /* COMpact 4410/2206 USB */
+	{ USB_DEVICE (ID_AUERSWALD, 0x00F1) },          /* Comfort 2000 System Telephone */
+	{ USB_DEVICE (ID_AUERSWALD, 0x00F2) },          /* Comfort 1200 System Telephone */
+        { }			                        /* Terminating entry */
+};
+
+/* Standard module device table */
+MODULE_DEVICE_TABLE (usb, auerswald_ids);
+
+/* Standard usb driver struct */
+static struct usb_driver auerswald_driver = {
+	name:		"auerswald",
+	probe:		auerswald_probe,
+	disconnect:	auerswald_disconnect,
+	fops:		&auerswald_fops,
+	minor:		AUER_MINOR_BASE,
+	id_table:	auerswald_ids,
+};
+
+
+/* --------------------------------------------------------------------- */
+/* Module loading/unloading                                              */
+
+/* Driver initialisation. Called after module loading.
+   NOTE: there is no concurrency at _init
+*/
+static int __init auerswald_init (void)
+{
+	int result;
+	dbg ("init");
+
+	/* initialize the device table */
+	memset (&dev_table, 0, sizeof(dev_table));
+	init_MUTEX (&dev_table_mutex);
+
+	/* register driver at the USB subsystem */
+	result = usb_register (&auerswald_driver);
+	if (result < 0) {
+		err ("driver could not be registered");
+		return -1;
+	}
+	return 0;
+}
+
+/* Driver deinit. Called before module removal.
+   NOTE: there is no concurrency at _cleanup
+*/
+static void __exit auerswald_cleanup (void)
+{
+	dbg ("cleanup");
+	usb_deregister (&auerswald_driver);
+}
+
+/* --------------------------------------------------------------------- */
+/* Linux device driver module description                                */
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+module_init (auerswald_init);
+module_exit (auerswald_cleanup);
+
+/* --------------------------------------------------------------------- */
+
diff -urN linux-2.4.19-pre2/drivers/usb/hcd.c linux-2.4.19-pre3/drivers/usb/hcd.c
--- linux-2.4.19-pre2/drivers/usb/hcd.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/usb/hcd.c	Mon Mar 11 14:13:29 2002
@@ -624,7 +624,7 @@
 #ifndef __sparc__
 	sprintf (buf, "%d", dev->irq);
 #else
-	bufp = __irq_itoa(irq);
+	bufp = __irq_itoa(dev->irq);
 #endif
 	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
 			!= 0) {
diff -urN linux-2.4.19-pre2/drivers/usb/hpusbscsi.c linux-2.4.19-pre3/drivers/usb/hpusbscsi.c
--- linux-2.4.19-pre2/drivers/usb/hpusbscsi.c	Tue Oct  9 15:15:02 2001
+++ linux-2.4.19-pre3/drivers/usb/hpusbscsi.c	Mon Mar 11 14:13:29 2002
@@ -185,7 +185,8 @@
 		tmp = tmp->next;
 		o = (struct hpusbscsi *)old;
 		usb_unlink_urb(&o->controlurb);
-		scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl);
+		if(scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl)<0)
+			printk(KERN_CRIT"Deregistering failed!\n");
 		kfree(old);
 	}
 
@@ -270,7 +271,13 @@
 	/* Now we need to decide which callback to give to the urb we send the command with */
 
 	if (!srb->bufflen) {
-		usb_callback = simple_command_callback;
+		if (srb->cmnd[0] == REQUEST_SENSE){
+			/* the usual buffer is not used, needs a special case */
+			hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
+			usb_callback = request_sense_callback;
+		} else {
+			usb_callback = simple_command_callback;
+		}
 	} else {
         	if (srb->use_sg) {
 			usb_callback = scatter_gather_callback;
@@ -332,8 +339,8 @@
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
 
 	printk(KERN_DEBUG"SCSI reset requested.\n");
-	usb_reset_device(hpusbscsi->dev);
-	printk(KERN_DEBUG"SCSI reset completed.\n");
+	//usb_reset_device(hpusbscsi->dev);
+	//printk(KERN_DEBUG"SCSI reset completed.\n");
 	hpusbscsi->state = HP_STATE_FREE;
 
 	return 0;
@@ -342,10 +349,9 @@
 static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
 {
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
-	printk(KERN_DEBUG"Requested is canceled.\n");
+	printk(KERN_DEBUG"Request is canceled.\n");
 
 	usb_unlink_urb(&hpusbscsi->dataurb);
-	usb_unlink_urb(&hpusbscsi->controlurb);
 	hpusbscsi->state = HP_STATE_FREE;
 
 	return SCSI_ABORT_PENDING;
@@ -373,7 +379,7 @@
 		return;
 	}
 	hpusbscsi->srb->result &= SCSI_ERR_MASK;
-	hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte<<1;
+	hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte;
 
 	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
 		/* we do a callback to the scsi layer if and only if all data has been transfered */
@@ -453,7 +459,7 @@
 
         res = usb_submit_urb(u);
         if (res)
-                hpusbscsi->state = HP_STATE_ERROR;
+        	handle_usb_error(hpusbscsi);
 	TRACE_STATE;
 }
 
@@ -469,7 +475,7 @@
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
 		if (u->status < 0)
-			hpusbscsi->state = HP_STATE_ERROR;
+			handle_usb_error(hpusbscsi);
 		else
 			hpusbscsi->state = HP_STATE_WAIT;
 		TRACE_STATE;
@@ -509,11 +515,34 @@
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
 		hpusbscsi->state = HP_STATE_WORKING;
 	TRACE_STATE;
-	} else {
-		if (hpusbscsi->scallback != NULL)
-			hpusbscsi->scallback(hpusbscsi->srb);
-		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
 	}
 }
 
+static void request_sense_callback (struct urb *u)
+{
+	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+	if (u->status<0) {
+                handle_usb_error(hpusbscsi);
+		return;
+        }
+
+	FILL_BULK_URB(
+		u,
+		hpusbscsi->dev,
+		hpusbscsi->current_data_pipe,
+		hpusbscsi->srb->sense_buffer,
+		SCSI_SENSE_BUFFERSIZE,
+		simple_done,
+		hpusbscsi
+	);
+
+	if (0 > usb_submit_urb(u)) {
+		handle_usb_error(hpusbscsi);
+		return;
+	}
+	if (hpusbscsi->state != HP_STATE_PREMATURE)
+		hpusbscsi->state = HP_STATE_WORKING;
+}
+
+
diff -urN linux-2.4.19-pre2/drivers/usb/hpusbscsi.h linux-2.4.19-pre3/drivers/usb/hpusbscsi.h
--- linux-2.4.19-pre2/drivers/usb/hpusbscsi.h	Fri Oct  5 12:04:51 2001
+++ linux-2.4.19-pre3/drivers/usb/hpusbscsi.h	Mon Mar 11 14:13:29 2002
@@ -51,7 +51,8 @@
 static void simple_command_callback(struct urb *u);
 static void scatter_gather_callback(struct urb *u);
 static void simple_payload_callback (struct urb *u);
-static void  control_interrupt_callback (struct urb *u);
+static void control_interrupt_callback (struct urb *u);
+static void request_sense_callback (struct urb *u);
 static void simple_done (struct urb *u);
 static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
 static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
diff -urN linux-2.4.19-pre2/drivers/usb/kaweth.c linux-2.4.19-pre3/drivers/usb/kaweth.c
--- linux-2.4.19-pre2/drivers/usb/kaweth.c	Tue Nov 13 09:19:41 2001
+++ linux-2.4.19-pre3/drivers/usb/kaweth.c	Mon Mar 11 14:13:29 2002
@@ -238,8 +238,7 @@
 		return -EBUSY;
 	}
 
-	dr = kmalloc(sizeof(devrequest), 
-                     in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	dr = kmalloc(sizeof(devrequest), GFP_ATOMIC);
 
 	if(!dr)
 	{
@@ -587,14 +586,10 @@
 {
 	struct kaweth_device *kaweth = urb->context;
 
-	spin_lock(&kaweth->device_lock);
-
 	if (urb->status)
 		kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
 
 	netif_wake_queue(kaweth->net);
-
-	spin_unlock(&kaweth->device_lock);
 }
 
 /****************************************************************
@@ -722,6 +717,7 @@
 	kaweth->stats.tx_errors++;
 	net->trans_start = jiffies;
 
+	kaweth->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
 	usb_unlink_urb(kaweth->tx_urb);
 }
 
@@ -825,6 +821,7 @@
 
 		/* Device will now disappear for a moment...  */
 		kaweth_info("Firmware loaded.  I'll be back...");
+		kfree(kaweth);
 		return NULL;
 	}
 
@@ -927,6 +924,9 @@
 		return;
 	}
 
+	usb_unlink_urb(kaweth->rx_urb);
+	usb_unlink_urb(kaweth->tx_urb);
+
 	if(kaweth->net) {
 		if(kaweth->net->flags & IFF_UP) {
 			kaweth_dbg("Closing net device");
diff -urN linux-2.4.19-pre2/drivers/usb/ov511.c linux-2.4.19-pre3/drivers/usb/ov511.c
--- linux-2.4.19-pre2/drivers/usb/ov511.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/ov511.c	Mon Mar 11 14:13:29 2002
@@ -1,7 +1,7 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
  *
- * Copyright (c) 1999-2001 Mark W. McClelland
+ * Copyright (c) 1999-2002 Mark W. McClelland
  * Original decompression code Copyright 1998-2000 OmniVision Technologies
  * Many improvements by Bret Wallach <bwallac1@san.rr.com>
  * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
@@ -57,7 +57,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.48a for Linux 2.4"
+#define DRIVER_VERSION "v1.50 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 \
@@ -308,7 +308,7 @@
 static inline int sensor_get_picture(struct usb_ov511 *, 
 				     struct video_picture *);
 static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
-static int ov511_control_ioctl(struct inode *, struct file *, unsigned int,
+static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
 			       unsigned long);
 
 /**********************************************************************
@@ -331,6 +331,7 @@
 	{ 100, "Lifeview RoboCam" },
 	{ 102, "AverMedia InterCam Elite" },
 	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
+	{ 192, "Webeye 2000B" },
 	{  -1, NULL }
 };
 
@@ -493,7 +494,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 static struct file_operations ov511_control_fops = {
-	ioctl:		ov511_control_ioctl,
+	ioctl:		ov51x_control_ioctl,
 };
 
 #define YES_NO(x) ((x) ? "yes" : "no")
@@ -505,29 +506,29 @@
 {
 	char *out = page;
 	int i, j, len;
-	struct usb_ov511 *ov511 = data;
+	struct usb_ov511 *ov = data;
 	struct video_picture p;
 	unsigned char exp;
 
-	if (!ov511 || !ov511->dev)
+	if (!ov || !ov->dev)
 		return -ENODEV;
 
-	sensor_get_picture(ov511, &p);
-	sensor_get_exposure(ov511, &exp);
+	sensor_get_picture(ov, &p);
+	sensor_get_exposure(ov, &exp);
 
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
 
 	out += sprintf(out, "driver_version  : %s\n", DRIVER_VERSION);
-	out += sprintf(out, "custom_id       : %d\n", ov511->customid);
-	out += sprintf(out, "model           : %s\n", ov511->desc ?
-		       clist[ov511->desc].description : "unknown");
-	out += sprintf(out, "streaming       : %s\n", YES_NO(ov511->streaming));
-	out += sprintf(out, "grabbing        : %s\n", YES_NO(ov511->grabbing));
-	out += sprintf(out, "compress        : %s\n", YES_NO(ov511->compress));
-	out += sprintf(out, "subcapture      : %s\n", YES_NO(ov511->sub_flag));
+	out += sprintf(out, "custom_id       : %d\n", ov->customid);
+	out += sprintf(out, "model           : %s\n", ov->desc ?
+		       clist[ov->desc].description : "unknown");
+	out += sprintf(out, "streaming       : %s\n", YES_NO(ov->streaming));
+	out += sprintf(out, "grabbing        : %s\n", YES_NO(ov->grabbing));
+	out += sprintf(out, "compress        : %s\n", YES_NO(ov->compress));
+	out += sprintf(out, "subcapture      : %s\n", YES_NO(ov->sub_flag));
 	out += sprintf(out, "sub_size        : %d %d %d %d\n",
-		       ov511->subx, ov511->suby, ov511->subw, ov511->subh);
+		       ov->subx, ov->suby, ov->subw, ov->subh);
 	out += sprintf(out, "data_format     : %s\n",
 		       force_rgb ? "RGB" : "BGR");
 	out += sprintf(out, "brightness      : %d\n", p.brightness >> 8);
@@ -539,12 +540,12 @@
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
 		out += sprintf(out, "frame           : %d\n", i);
 		out += sprintf(out, "  depth         : %d\n",
-			       ov511->frame[i].depth);
+			       ov->frame[i].depth);
 		out += sprintf(out, "  size          : %d %d\n",
-			       ov511->frame[i].width, ov511->frame[i].height);
+			       ov->frame[i].width, ov->frame[i].height);
 		out += sprintf(out, "  format        : ");
 		for (j = 0; plist[j].num >= 0; j++) {
-			if (plist[j].num == ov511->frame[i].format) {
+			if (plist[j].num == ov->frame[i].format) {
 				out += sprintf(out, "%s\n", plist[j].name);
 				break;
 			}
@@ -552,29 +553,28 @@
 		if (plist[j].num < 0)
 			out += sprintf(out, "unknown\n");
 		out += sprintf(out, "  data_buffer   : 0x%p\n",
-			       ov511->frame[i].data);
+			       ov->frame[i].data);
 	}
-	out += sprintf(out, "snap_enabled    : %s\n",
-		       YES_NO(ov511->snap_enabled));
+	out += sprintf(out, "snap_enabled    : %s\n", YES_NO(ov->snap_enabled));
 	out += sprintf(out, "bridge          : %s\n",
-		       ov511->bridge == BRG_OV511 ? "OV511" :
-			ov511->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov511->bridge == BRG_OV518 ? "OV518" :
-			ov511->bridge == BRG_OV518PLUS ? "OV518+" :
+		       ov->bridge == BRG_OV511 ? "OV511" :
+			ov->bridge == BRG_OV511PLUS ? "OV511+" :
+			ov->bridge == BRG_OV518 ? "OV518" :
+			ov->bridge == BRG_OV518PLUS ? "OV518+" :
 			"unknown");
 	out += sprintf(out, "sensor          : %s\n",
-		       ov511->sensor == SEN_OV6620 ? "OV6620" :
-			ov511->sensor == SEN_OV6630 ? "OV6630" :
-			ov511->sensor == SEN_OV7610 ? "OV7610" :
-			ov511->sensor == SEN_OV7620 ? "OV7620" :
-			ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
-			ov511->sensor == SEN_OV8600 ? "OV8600" :
-			ov511->sensor == SEN_KS0127 ? "KS0127" :
-			ov511->sensor == SEN_KS0127B ? "KS0127B" :
-			ov511->sensor == SEN_SAA7111A ? "SAA7111A" :
+		       ov->sensor == SEN_OV6620 ? "OV6620" :
+			ov->sensor == SEN_OV6630 ? "OV6630" :
+			ov->sensor == SEN_OV7610 ? "OV7610" :
+			ov->sensor == SEN_OV7620 ? "OV7620" :
+			ov->sensor == SEN_OV7620AE ? "OV7620AE" :
+			ov->sensor == SEN_OV8600 ? "OV8600" :
+			ov->sensor == SEN_KS0127 ? "KS0127" :
+			ov->sensor == SEN_KS0127B ? "KS0127B" :
+			ov->sensor == SEN_SAA7111A ? "SAA7111A" :
 			"unknown");
-	out += sprintf(out, "packet_size     : %d\n", ov511->packet_size);
-	out += sprintf(out, "framebuffer     : 0x%p\n", ov511->fbuf);
+	out += sprintf(out, "packet_size     : %d\n", ov->packet_size);
+	out += sprintf(out, "framebuffer     : 0x%p\n", ov->fbuf);
 
 	len = out - page;
 	len -= off;
@@ -607,16 +607,16 @@
 {
 	char *out = page;
 	int len, status;
-	struct usb_ov511 *ov511 = data;
+	struct usb_ov511 *ov = data;
 
-	if (!ov511 || !ov511->dev)
+	if (!ov || !ov->dev)
 		return -ENODEV;
 
-	status = ov51x_check_snapshot(ov511);
+	status = ov51x_check_snapshot(ov);
 	out += sprintf(out, "%d", status);
 
 	if (status)
-		ov51x_clear_snapshot(ov511);
+		ov51x_clear_snapshot(ov);
 
 	len = out - page;
 	len -= off;
@@ -636,18 +636,19 @@
 static void 
 create_proc_ov511_cam(struct usb_ov511 *ov511)
 {
-	char dirname[4];
+	char dirname[10];
 
 	if (!ov511_proc_entry || !ov511)
 		return;
 
 	/* Create per-device directory */
-	sprintf(dirname, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov511->vdev.minor);
 	PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);
 	ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR,
 		ov511_proc_entry);
 	if (!ov511->proc_devdir)
 		return;
+	ov511->proc_devdir->owner = THIS_MODULE;
 
 	/* Create "info" entry (human readable device information) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);
@@ -656,6 +657,7 @@
 		ov511_read_proc_info, ov511);
 	if (!ov511->proc_info)
 		return;
+	ov511->proc_info->owner = THIS_MODULE;
 
 	/* Don't create it if old snapshot mode on (would cause race cond.) */
 	if (!snapshot) {
@@ -667,6 +669,7 @@
 		if (!ov511->proc_button)
 			return;
 	}
+	ov511->proc_button->owner = THIS_MODULE;
 
 	/* Create "control" entry (ioctl() interface) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
@@ -677,6 +680,7 @@
 		unlock_kernel();
 		return;
 	}
+	ov511->proc_control->owner = THIS_MODULE;
 	ov511->proc_control->data = ov511;
 	ov511->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
@@ -685,12 +689,12 @@
 static void 
 destroy_proc_ov511_cam(struct usb_ov511 *ov511)
 {
-	char dirname[4];
+	char dirname[10];
 	
 	if (!ov511 || !ov511->proc_devdir)
 		return;
 
-	sprintf(dirname, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov511->vdev.minor);
 
 	/* Destroy "control" entry */
 	if (ov511->proc_control) {
@@ -758,18 +762,22 @@
  *
  **********************************************************************/
 
+/* Write an OV51x register */
 static int 
-ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
-	rc = usb_control_msg(dev,
-			     usb_sndctrlpipe(dev, 0),
+	down(&ov->cbuf_lock);
+	ov->cbuf[0] = value;
+	rc = usb_control_msg(ov->dev,
+			     usb_sndctrlpipe(ov->dev, 0),
 			     2 /* REG_IO */,
 			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &value, 1, HZ);	
+			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);	
+	up(&ov->cbuf_lock);
 
 	if (rc < 0)
 		err("reg write: error %d", rc);
@@ -777,45 +785,48 @@
 	return rc;
 }
 
+/* Read from an OV51x register */
 /* returns: negative is error, pos or zero is data */
 static int 
-ov511_reg_read(struct usb_device *dev, unsigned char reg)
+reg_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
-	unsigned char buffer[1];
 
-	rc = usb_control_msg(dev,
-			     usb_rcvctrlpipe(dev, 0),
+	down(&ov->cbuf_lock);
+	rc = usb_control_msg(ov->dev,
+			     usb_rcvctrlpipe(ov->dev, 0),
 			     2 /* REG_IO */,
 			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
-			     0, (__u16)reg, buffer, 1, HZ);
+			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);
                                
-	PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]);
+	PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
 	
-	if (rc < 0) {
+	if (rc < 0)
 		err("reg read: error %d", rc);
-		return rc;
-	} else {
-		return buffer[0];	
-	}
+	else
+		rc = ov->cbuf[0];	
+
+	up(&ov->cbuf_lock);
+
+	return rc;
 }
 
 /*
- * Writes bits at positions specified by mask to a reg. Bits that are in
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
  * that are in the same position as 0's in "mask" are preserved, regardless 
  * of their respective state in "value".
  */
 static int 
-ov511_reg_write_mask(struct usb_device *dev,
-		     unsigned char reg,
-		     unsigned char value,
-		     unsigned char mask)
+reg_w_mask(struct usb_ov511 *ov,
+	   unsigned char reg,
+	   unsigned char value,
+	   unsigned char mask)
 {
 	int ret;
 	unsigned char oldval, newval;
 
-	ret = ov511_reg_read(dev, reg);
+	ret = reg_r(ov, reg);
 	if (ret < 0)
 		return ret;
 
@@ -824,31 +835,30 @@
 	value &= mask;			/* Enforce mask on value */
 	newval = oldval | value;	/* Set the desired bits */
 
-	return (ov511_reg_write(dev, reg, newval));
+	return (reg_w(ov, reg, newval));
 }
 
-/* Writes multiple (n) values to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */
+/* 
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
 static int 
-ov518_reg_write_multi(struct usb_device *dev,
-		      unsigned char reg,
-		      unsigned char *values,
-		      int n)
+ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 {
 	int rc;
 
-	PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n);  // FIXME
+	PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
 
-	if (values == NULL) {
-		err("reg write multiple: NULL buffer");
-		return -EINVAL;
-	}
+	down(&ov->cbuf_lock);
+
+	*((u32 *)ov->cbuf) = __cpu_to_le32(val);
 
-	rc = usb_control_msg(dev,
-			     usb_sndctrlpipe(dev, 0),
+	rc = usb_control_msg(ov->dev,
+			     usb_sndctrlpipe(ov->dev, 0),
 			     2 /* REG_IO */,
 			     USB_TYPE_CLASS | USB_RECIP_DEVICE,
-			     0, (__u16)reg, values, n, HZ);	
+			     0, (__u16)reg, ov->cbuf, n, HZ);
+	up(&ov->cbuf_lock);
 
 	if (rc < 0)
 		err("reg write multiple: error %d", rc);
@@ -857,12 +867,12 @@
 }
 
 static int 
-ov511_upload_quan_tables(struct usb_device *dev)
+ov511_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable511;
 	unsigned char *pUVTable = uvQuanTable511;
 	unsigned char val0, val1;
-	int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN;
+	int i, rc, reg = R511_COMP_LUT_BEGIN;
 
 	PDEBUG(4, "Uploading quantization tables");
 
@@ -875,7 +885,7 @@
 			val0 &= 0x0f;
 			val1 &= 0x0f;
 			val0 |= val1 << 4;
-			rc = ov511_reg_write(dev, reg, val0);
+			rc = reg_w(ov, reg, val0);
 			if (rc < 0)
 				return rc;
 		}
@@ -887,8 +897,7 @@
 			val0 &= 0x0f;
 			val1 &= 0x0f;
 			val0 |= val1 << 4;
-			rc = ov511_reg_write(dev, reg + OV511_QUANTABLESIZE / 2,
-				val0);
+			rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
 			if (rc < 0)
 				return rc;
 		}
@@ -901,12 +910,12 @@
 
 /* OV518 quantization tables are 8x4 (instead of 8x8) */
 static int 
-ov518_upload_quan_tables(struct usb_device *dev)
+ov518_upload_quan_tables(struct usb_ov511 *ov)
 {
 	unsigned char *pYTable = yQuanTable518;
 	unsigned char *pUVTable = uvQuanTable518;
 	unsigned char val0, val1;
-	int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN;
+	int i, rc, reg = R511_COMP_LUT_BEGIN;
 
 	PDEBUG(4, "Uploading quantization tables");
 
@@ -919,7 +928,7 @@
 			val0 &= 0x0f;
 			val1 &= 0x0f;
 			val0 |= val1 << 4;
-			rc = ov511_reg_write(dev, reg, val0);
+			rc = reg_w(ov, reg, val0);
 			if (rc < 0)
 				return rc;
 		}
@@ -931,8 +940,7 @@
 			val0 &= 0x0f;
 			val1 &= 0x0f;
 			val0 |= val1 << 4;
-			rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2,
-				val0);
+			rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
 			if (rc < 0)
 				return rc;
 		}
@@ -943,13 +951,39 @@
 	return 0;
 }
 
+static int 
+ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
+{
+	int rc;
+		
+	/* Setting bit 0 not allowed on 518/518Plus */
+	if (ov->bclass == BCL_OV518)
+		reset_type &= 0xfe;
+
+	PDEBUG(4, "Reset: type=0x%X", reset_type);
+
+	rc = reg_w(ov, R51x_SYS_RESET, reset_type);
+	rc = reg_w(ov, R51x_SYS_RESET, 0);
+
+	if (rc < 0)
+		err("reset: command failed");
+
+	return rc;
+}
+
+/**********************************************************************
+ *
+ * I2C (sensor) I/O
+ *
+ **********************************************************************/
+
 /* NOTE: Do not call this function directly!
  * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from ov51x_i2c_write(). Note that this function
+ * This is normally only called from i2c_w(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
 static int 
-ov518_i2c_write_internal(struct usb_device *dev,
+ov518_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
 {
@@ -958,15 +992,15 @@
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
 	/* Select camera register */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
+	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
 	if (rc < 0) goto error;
 
 	/* Write "value" to I2C data port of OV511 */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);
+	rc = reg_w(ov, R51x_I2C_DATA, value);
 	if (rc < 0) goto error;
 
 	/* Initiate 3-byte write cycle */
-	rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01);
+	rc = reg_w(ov, R518_I2C_CTL, 0x01);
 	if (rc < 0) goto error;
 
 	return 0;
@@ -978,7 +1012,7 @@
 
 /* NOTE: Do not call this function directly! */
 static int 
-ov511_i2c_write_internal(struct usb_device *dev,
+ov511_i2c_write_internal(struct usb_ov511 *ov,
 			 unsigned char reg,
 			 unsigned char value)
 {
@@ -989,19 +1023,18 @@
 	/* Three byte write cycle */
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE,
-				     reg);
+		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
 		if (rc < 0) goto error;
 
 		/* Write "value" to I2C data port of OV511 */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);	
+		rc = reg_w(ov, R51x_I2C_DATA, value);	
 		if (rc < 0) goto error;
 
 		/* Initiate 3-byte write cycle */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
+		rc = reg_w(ov, R511_I2C_CTL, 0x01);
 		if (rc < 0) goto error;
 
-		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
@@ -1009,7 +1042,7 @@
 			break;
 #if 0
 		/* I2C abort */	
-		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+		reg_w(ov, R511_I2C_CTL, 0x10);
 #endif
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
@@ -1027,27 +1060,27 @@
 
 /* NOTE: Do not call this function directly!
  * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from ov51x_i2c_read(). Note that this function
+ * This is normally only called from i2c_r(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
 static int 
-ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg)
+ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value;
 
 	/* Select camera register */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
+	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
 	if (rc < 0) goto error;
 
 	/* Initiate 2-byte write cycle */
-	rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x03);
+	rc = reg_w(ov, R518_I2C_CTL, 0x03);
 	if (rc < 0) goto error;
 
 	/* Initiate 2-byte read cycle */
-	rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05);
+	rc = reg_w(ov, R518_I2C_CTL, 0x05);
 	if (rc < 0) goto error;
 
-	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
@@ -1061,22 +1094,21 @@
 /* NOTE: Do not call this function directly!
  * returns: negative is error, pos or zero is data */
 static int 
-ov511_i2c_read_internal(struct usb_device *dev, unsigned char reg)
+ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc, value, retries;
 
 	/* Two byte write cycle */
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE,
-				     reg);
+		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
 		if (rc < 0) goto error;
 
 		/* Initiate 2-byte write cycle */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
+		rc = reg_w(ov, R511_I2C_CTL, 0x03);
 		if (rc < 0) goto error;
 
-		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
@@ -1084,7 +1116,7 @@
 			break;
 
 		/* I2C abort */	
-		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+		reg_w(ov, R511_I2C_CTL, 0x10);
 
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
@@ -1096,10 +1128,10 @@
 	/* Two byte read cycle */
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
-		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+		rc = reg_w(ov, R511_I2C_CTL, 0x05);
 		if (rc < 0) goto error;
 
-		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
 		if (rc < 0) goto error;
 
@@ -1107,7 +1139,7 @@
 			break;
 
 		/* I2C abort */	
-		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+		rc = reg_w(ov, R511_I2C_CTL, 0x10);
 		if (rc < 0) goto error;
 
 		if (--retries < 0) {
@@ -1117,12 +1149,12 @@
 		}
 	}
 
-	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 		
-	/* This is needed to make ov51x_i2c_write() work */
-	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+	/* This is needed to make i2c_w() work */
+	rc = reg_w(ov, R511_I2C_CTL, 0x05);
 	if (rc < 0)
 		goto error;
 	
@@ -1135,48 +1167,42 @@
 
 /* returns: negative is error, pos or zero is data */
 static int 
-ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg)
+i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
-	struct usb_device *dev = ov511->dev;
 
-	down(&ov511->i2c_lock);
+	down(&ov->i2c_lock);
 
-	if (dev->descriptor.idProduct == PROD_OV518 ||
-	    dev->descriptor.idProduct == PROD_OV518PLUS)
-		rc = ov518_i2c_read_internal(dev, reg);
+	if (ov->bclass == BCL_OV518)
+		rc = ov518_i2c_read_internal(ov, reg);
 	else
-		rc = ov511_i2c_read_internal(dev, reg);
+		rc = ov511_i2c_read_internal(ov, reg);
 
-	up(&ov511->i2c_lock);
+	up(&ov->i2c_lock);
 
 	return rc;
 }
 
 static int 
-ov51x_i2c_write(struct usb_ov511 *ov511,
-		unsigned char reg,
-		unsigned char value)
+i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
-	struct usb_device *dev = ov511->dev;
 
-	down(&ov511->i2c_lock);
+	down(&ov->i2c_lock);
 
-	if (dev->descriptor.idProduct == PROD_OV518 ||
-	    dev->descriptor.idProduct == PROD_OV518PLUS)
-		rc = ov518_i2c_write_internal(dev, reg, value);
+	if (ov->bclass == BCL_OV518)
+		rc = ov518_i2c_write_internal(ov, reg, value);
 	else
-		rc = ov511_i2c_write_internal(dev, reg, value);
+		rc = ov511_i2c_write_internal(ov, reg, value);
 
-	up(&ov511->i2c_lock);
+	up(&ov->i2c_lock);
 
 	return rc;
 }
 
 /* Do not call this function directly! */
 static int 
-ov51x_i2c_write_mask_internal(struct usb_device *dev,
+ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
 			      unsigned char reg,
 			      unsigned char value,
 			      unsigned char mask)
@@ -1187,11 +1213,10 @@
 	if (mask == 0xff) {
 		newval = value;
 	} else {
-		if (dev->descriptor.idProduct == PROD_OV518 ||
-		    dev->descriptor.idProduct == PROD_OV518PLUS)
-			rc = ov518_i2c_read_internal(dev, reg);
+		if (ov->bclass == BCL_OV518)
+			rc = ov518_i2c_read_internal(ov, reg);
 		else
-			rc = ov511_i2c_read_internal(dev, reg);
+			rc = ov511_i2c_read_internal(ov, reg);
 		if (rc < 0)
 			return rc;
 
@@ -1201,11 +1226,10 @@
 		newval = oldval | value;	/* Set the desired bits */
 	}
 
-	if (dev->descriptor.idProduct == PROD_OV518 ||
-	    dev->descriptor.idProduct == PROD_OV518PLUS)
-		return (ov518_i2c_write_internal(dev, reg, newval));
+	if (ov->bclass == BCL_OV518)
+		return (ov518_i2c_write_internal(ov, reg, newval));
 	else
-		return (ov511_i2c_write_internal(dev, reg, newval));
+		return (ov511_i2c_write_internal(ov, reg, newval));
 }
 
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
@@ -1214,126 +1238,138 @@
  * of their respective state in "value".
  */
 static int 
-ov51x_i2c_write_mask(struct usb_ov511 *ov511,
-		     unsigned char reg,
-		     unsigned char value,
-		     unsigned char mask)
+i2c_w_mask(struct usb_ov511 *ov,
+	   unsigned char reg,
+	   unsigned char value,
+	   unsigned char mask)
 {
 	int rc;
-	struct usb_device *dev = ov511->dev;
 
-	down(&ov511->i2c_lock);
-	rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask);
-	up(&ov511->i2c_lock);
+	down(&ov->i2c_lock);
+	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
+	up(&ov->i2c_lock);
 
 	return rc;
 }
 
 /* Write to a specific I2C slave ID and register, using the specified mask */
 static int 
-ov51x_i2c_write_slave(struct usb_ov511 *ov511,
-		      unsigned char slave,
-		      unsigned char reg,
-		      unsigned char value,
-		      unsigned char mask)
+i2c_w_slave(struct usb_ov511 *ov,
+	    unsigned char slave,
+	    unsigned char reg,
+	    unsigned char value,
+	    unsigned char mask)
 {
 	int rc = 0;
-	struct usb_device *dev = ov511->dev;
 
-	down(&ov511->i2c_lock);
+	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) {
+	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) {
+	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask);
+	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
 	/* Don't bail out yet if error; IDs must be restored */
 
 	/* Restore primary IDs */
-	slave = ov511->primary_i2c_slave;
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) {
+	slave = ov->primary_i2c_slave;
+	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) {
+	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
 out:
-	up(&ov511->i2c_lock);
+	up(&ov->i2c_lock);
 	return rc;
 }
 
 /* Read from a specific I2C slave ID and register */
 static int 
-ov51x_i2c_read_slave(struct usb_ov511 *ov511,
-		     unsigned char slave,
-		     unsigned char reg)
+i2c_r_slave(struct usb_ov511 *ov,
+	    unsigned char slave,
+	    unsigned char reg)
 {
 	int rc;
-	struct usb_device *dev = ov511->dev;
 
-	down(&ov511->i2c_lock);
+	down(&ov->i2c_lock);
 
 	/* Set new slave IDs */
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) {
+	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) {
+	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	if (dev->descriptor.idProduct == PROD_OV518 ||
-	    dev->descriptor.idProduct == PROD_OV518PLUS)
-		rc = ov518_i2c_read_internal(dev, reg);
+	if (ov->bclass == BCL_OV518)
+		rc = ov518_i2c_read_internal(ov, reg);
 	else
-		rc = ov511_i2c_read_internal(dev, reg);
+		rc = ov511_i2c_read_internal(ov, reg);
 	/* Don't bail out yet if error; IDs must be restored */
 
 	/* Restore primary IDs */
-	slave = ov511->primary_i2c_slave;
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) {
+	slave = ov->primary_i2c_slave;
+	if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) {
+	if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) {
 		rc = -EIO;
 		goto out;
 	}
 
 out:
-	up(&ov511->i2c_lock);
+	up(&ov->i2c_lock);
 	return rc;
 }
 
+/* Sets I2C read and write slave IDs. Returns <0 for error */
 static int 
-ov511_write_regvals(struct usb_ov511 *ov511,
-		    struct ov511_regvals * pRegvals)
+ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
+{
+	down(&ov->i2c_lock);
+
+	if (reg_w(ov, R51x_I2C_W_SID, sid) < 0)
+		return -EIO;
+
+	if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0)
+		return -EIO;
+
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+		return -EIO;
+
+	up(&ov->i2c_lock);
+
+	return 0;
+}
+
+static int 
+write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
 {
 	int rc;
-	struct usb_device *dev = ov511->dev;
 
 	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
-			if ((rc = ov511_reg_write(dev, pRegvals->reg,
-			                          pRegvals->val)) < 0)
+			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
 				goto error;
 		} else if (pRegvals->bus == OV511_I2C_BUS) {
-			if ((rc = ov51x_i2c_write(ov511, pRegvals->reg, 
-			                          pRegvals->val)) < 0)
+			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
 				goto error;
 		} else {
 			err("Bad regval array");
@@ -1351,57 +1387,60 @@
 
 #ifdef OV511_DEBUG 
 static void 
-ov511_dump_i2c_range(struct usb_ov511 *ov511, int reg1, int regn)
+dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
 	int rc;
+
 	for (i = reg1; i <= regn; i++) {
-		rc = ov51x_i2c_read(ov511, i);
+		rc = i2c_r(ov, i);
 		info("OV7610[0x%X] = 0x%X", i, rc);
 	}
 }
 
 static void 
-ov51x_dump_i2c_regs(struct usb_ov511 *ov511)
+dump_i2c_regs(struct usb_ov511 *ov)
 {
 	info("I2C REGS");
-	ov511_dump_i2c_range(ov511, 0x00, 0x7C);
+	dump_i2c_range(ov, 0x00, 0x7C);
 }
 
 static void 
-ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
+dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
 {
 	int i;
 	int rc;
+
 	for (i = reg1; i <= regn; i++) {
-	  rc = ov511_reg_read(dev, i);
-	  info("OV511[0x%X] = 0x%X", i, rc);
+		rc = reg_r(ov, i);
+		info("OV511[0x%X] = 0x%X", i, rc);
 	}
 }
 
+/* FIXME: Should there be an OV518 version of this? */
 static void 
-ov511_dump_regs(struct usb_device *dev)
+ov511_dump_regs(struct usb_ov511 *ov)
 {
 	info("CAMERA INTERFACE REGS");
-	ov511_dump_reg_range(dev, 0x10, 0x1f);
+	dump_reg_range(ov, 0x10, 0x1f);
 	info("DRAM INTERFACE REGS");
-	ov511_dump_reg_range(dev, 0x20, 0x23);
+	dump_reg_range(ov, 0x20, 0x23);
 	info("ISO FIFO REGS");
-	ov511_dump_reg_range(dev, 0x30, 0x31);
+	dump_reg_range(ov, 0x30, 0x31);
 	info("PIO REGS");
-	ov511_dump_reg_range(dev, 0x38, 0x39);
-	ov511_dump_reg_range(dev, 0x3e, 0x3e);
+	dump_reg_range(ov, 0x38, 0x39);
+	dump_reg_range(ov, 0x3e, 0x3e);
 	info("I2C REGS");
-	ov511_dump_reg_range(dev, 0x40, 0x49);
+	dump_reg_range(ov, 0x40, 0x49);
 	info("SYSTEM CONTROL REGS");
-	ov511_dump_reg_range(dev, 0x50, 0x55);
-	ov511_dump_reg_range(dev, 0x5e, 0x5f);
+	dump_reg_range(ov, 0x50, 0x55);
+	dump_reg_range(ov, 0x5e, 0x5f);
 	info("OmniCE REGS");
-	ov511_dump_reg_range(dev, 0x70, 0x79);
+	dump_reg_range(ov, 0x70, 0x79);
 	/* NOTE: Quantization tables are not readable. You will get the value
 	 * in reg. 0x79 for every table register */
-	ov511_dump_reg_range(dev, 0x80, 0x9f);
-	ov511_dump_reg_range(dev, 0xa0, 0xbf);
+	dump_reg_range(ov, 0x80, 0x9f);
+	dump_reg_range(ov, 0xa0, 0xbf);
 
 }
 #endif
@@ -1414,7 +1453,7 @@
 
 /* For as-yet unimplemented I2C interface */
 static void 
-call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd,
+call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd,
 		 void *arg)
 {
 	/* Do nothing */
@@ -1422,59 +1461,33 @@
 
 /*****************************************************************************/
 
-static int 
-ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type)
-{
-	int rc;
-		
-	/* Setting bit 0 not allowed on 518/518Plus */
-	if (ov511->bridge == BRG_OV518 ||
-	    ov511->bridge == BRG_OV518PLUS)
-		reset_type &= 0xfe;
-
-	PDEBUG(4, "Reset: type=0x%X", reset_type);
-
-	rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type);
-	rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0);
-
-	if (rc < 0)
-		err("reset: command failed");
-
-	return rc;
-}
-
 /* Temporarily stops OV511 from functioning. Must do this before changing
  * registers while the camera is streaming */
 static inline int 
-ov511_stop(struct usb_ov511 *ov511)
+ov51x_stop(struct usb_ov511 *ov)
 {
 	PDEBUG(4, "stopping");
-	ov511->stopped = 1;	
-	if (ov511->bridge == BRG_OV518 ||
-	    ov511->bridge == BRG_OV518PLUS)
-		return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET,
-					0x3a));
+	ov->stopped = 1;	
+	if (ov->bclass == BCL_OV518)
+		return (reg_w(ov, R51x_SYS_RESET, 0x3a));
 	else
-		return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET,
-					0x3d));
+		return (reg_w(ov, R51x_SYS_RESET, 0x3d));
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
 static inline int 
-ov511_restart(struct usb_ov511 *ov511)
+ov51x_restart(struct usb_ov511 *ov)
 {
-	if (ov511->stopped) {
+	if (ov->stopped) {
 		PDEBUG(4, "restarting");
-		ov511->stopped = 0;	
+		ov->stopped = 0;	
 
 		/* Reinitialize the stream */
-		if (ov511->bridge == BRG_OV518 ||
-		    ov511->bridge == BRG_OV518PLUS)
-			ov511_reg_write(ov511->dev, 0x2f, 0x80);
+		if (ov->bclass == BCL_OV518)
+			reg_w(ov, 0x2f, 0x80);
 
-		return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET,
-					0x00));
+		return (reg_w(ov, R51x_SYS_RESET, 0x00));
 	}
 
 	return 0;
@@ -1482,14 +1495,13 @@
 
 /* Resets the hardware snapshot button */
 static void 
-ov51x_clear_snapshot(struct usb_ov511 *ov511)
+ov51x_clear_snapshot(struct usb_ov511 *ov)
 {
-	if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) {
-		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
-		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
-		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
-	} else if (ov511->bridge == BRG_OV518 ||
-		   ov511->bridge == BRG_OV518PLUS) {
+	if (ov->bclass == BCL_OV511) {
+		reg_w(ov, R51x_SYS_SNAP, 0x01);
+		reg_w(ov, R51x_SYS_SNAP, 0x03);
+		reg_w(ov, R51x_SYS_SNAP, 0x01);
+	} else if (ov->bclass == BCL_OV518) {
 		warn("snapshot reset not supported yet on OV518(+)");
 	} else {
 		err("clear snap: invalid bridge type");
@@ -1500,19 +1512,18 @@
 /* Checks the status of the snapshot button. Returns 1 if it was pressed since
  * it was last cleared, and zero in all other cases (including errors) */
 static int 
-ov51x_check_snapshot(struct usb_ov511 *ov511)
+ov51x_check_snapshot(struct usb_ov511 *ov)
 {
 	int ret, status = 0;
 
-	if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) {
-		ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT);
+	if (ov->bclass == BCL_OV511) {
+		ret = reg_r(ov, R51x_SYS_SNAP);
 		if (ret < 0) {
 			err("Error checking snspshot status (%d)", ret);
 		} else if (ret & 0x08) {
 			status = 1;
 		}
-	} else if (ov511->bridge == BRG_OV518 ||
-		   ov511->bridge == BRG_OV518PLUS) {
+	} else if (ov->bclass == BCL_OV518) {
 		warn("snapshot check not supported yet on OV518(+)");
 	} else {
 		err("check snap: invalid bridge type");
@@ -1521,53 +1532,33 @@
 	return status;
 }
 
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int 
-ov51x_set_slave_ids(struct usb_ov511 *ov511,
-		    unsigned char write_id,
-		    unsigned char read_id)
-{
-	struct usb_device *dev = ov511->dev;
-
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, write_id) < 0)
-		return -EIO;
-
-	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, read_id) < 0)
-		return -EIO;
-
-	if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0)
-		return -EIO;
-
-	return 0;
-}
-
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
  * is synchronized. Returns <0 for failure.
  */
 static int 
-ov51x_init_ov_sensor(struct usb_ov511 *ov511)
+init_ov_sensor(struct usb_ov511 *ov)
 {
 	int i, success;
 
 	/* Reset the sensor */ 
-	if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO;
+	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
 
 	/* Wait for it to initialize */ 
 	schedule_timeout (1 + 150 * HZ / 1000);
 
 	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
-		if ((ov51x_i2c_read(ov511, OV7610_REG_ID_HIGH) == 0x7F) &&
-		    (ov51x_i2c_read(ov511, OV7610_REG_ID_LOW) == 0xA2)) {
+		if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+		    (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
 			success = 1;
 			continue;
 		}
 
 		/* Reset the sensor */ 
-		if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO;
+		if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
 		/* Wait for it to initialize */ 
 		schedule_timeout(1 + 150 * HZ / 1000);
 		/* Dummy read to sync I2C */
-		if (ov51x_i2c_read(ov511, 0x00) < 0) return -EIO;
+		if (i2c_r(ov, 0x00) < 0) return -EIO;
 	}
 
 	if (!success)
@@ -1579,16 +1570,16 @@
 }
 
 static int 
-ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+ov51x_set_packet_size(struct usb_ov511 *ov, int size)
 {
 	int alt, mult;
 
-	if (ov511_stop(ov511) < 0)
+	if (ov51x_stop(ov) < 0)
 		return -EIO;
 
 	mult = size >> 5;
 
-	if (ov511->bridge == BRG_OV511) {
+	if (ov->bridge == BRG_OV511) {
 		if (size == 0) alt = OV511_ALT_SIZE_0;
 		else if (size == 257) alt = OV511_ALT_SIZE_257;
 		else if (size == 513) alt = OV511_ALT_SIZE_513;
@@ -1598,7 +1589,7 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	} else if (ov511->bridge == BRG_OV511PLUS) {
+	} else if (ov->bridge == BRG_OV511PLUS) {
 		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
 		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
 		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
@@ -1611,8 +1602,7 @@
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
-	} else if (ov511->bridge == BRG_OV518 ||
-		   ov511->bridge == BRG_OV518PLUS) {
+	} else if (ov->bclass == BCL_OV518) {
 		if (size == 0) alt = OV518_ALT_SIZE_0;
 		else if (size == 128) alt = OV518_ALT_SIZE_128;
 		else if (size == 256) alt = OV518_ALT_SIZE_256;
@@ -1633,32 +1623,30 @@
 	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
 
 	// FIXME: Don't know how to do this on OV518 yet
-	if (ov511->bridge != BRG_OV518 &&
-	    ov511->bridge != BRG_OV518PLUS) {
-		if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+	if (ov->bclass == BCL_OV511) {
+		if (reg_w(ov, R51x_FIFO_PSIZE,
 				    mult) < 0) {
 			return -EIO;
 		}
 	}
 	
-	if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
+	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
 		err("Set packet size: set interface error");
 		return -EBUSY;
 	}
 
 	/* Initialize the stream */
-	if (ov511->bridge == BRG_OV518 ||
-	    ov511->bridge == BRG_OV518PLUS)
-		if (ov511_reg_write(ov511->dev, 0x2f, 0x80) < 0)
+	if (ov->bclass == BCL_OV518)
+		if (reg_w(ov, 0x2f, 0x80) < 0)
 			return -EIO;
 
 	// FIXME - Should we only reset the FIFO?
-	if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0)
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
 		return -EIO;
 
-	ov511->packet_size = size;
+	ov->packet_size = size;
 
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return 0;
@@ -1666,51 +1654,49 @@
 
 /* Upload compression params and quantization tables. Returns 0 for success. */
 static int
-ov511_init_compression(struct usb_ov511 *ov511)
+ov511_init_compression(struct usb_ov511 *ov)
 {
-	struct usb_device *dev = ov511->dev;
 	int rc = 0;
 
-	if (!ov511->compress_inited) {
+	if (!ov->compress_inited) {
 
-		ov511_reg_write(dev, 0x70, phy);
-		ov511_reg_write(dev, 0x71, phuv);
-		ov511_reg_write(dev, 0x72, pvy);
-		ov511_reg_write(dev, 0x73, pvuv);
-		ov511_reg_write(dev, 0x74, qhy);
-		ov511_reg_write(dev, 0x75, qhuv);
-		ov511_reg_write(dev, 0x76, qvy);
-		ov511_reg_write(dev, 0x77, qvuv);
+		reg_w(ov, 0x70, phy);
+		reg_w(ov, 0x71, phuv);
+		reg_w(ov, 0x72, pvy);
+		reg_w(ov, 0x73, pvuv);
+		reg_w(ov, 0x74, qhy);
+		reg_w(ov, 0x75, qhuv);
+		reg_w(ov, 0x76, qvy);
+		reg_w(ov, 0x77, qvuv);
 
-		if (ov511_upload_quan_tables(dev) < 0) {
+		if (ov511_upload_quan_tables(ov) < 0) {
 			err("Error uploading quantization tables");
 			rc = -EIO;
 			goto out;
 		}
 	}
 
-	ov511->compress_inited = 1;
+	ov->compress_inited = 1;
 out:	
 	return rc;
 }
 
 /* Upload compression params and quantization tables. Returns 0 for success. */
 static int
-ov518_init_compression(struct usb_ov511 *ov511)
+ov518_init_compression(struct usb_ov511 *ov)
 {
-	struct usb_device *dev = ov511->dev;
 	int rc = 0;
 
-	if (!ov511->compress_inited) {
+	if (!ov->compress_inited) {
 
-		if (ov518_upload_quan_tables(dev) < 0) {
+		if (ov518_upload_quan_tables(ov) < 0) {
 			err("Error uploading quantization tables");
 			rc = -EIO;
 			goto out;
 		}
 	}
 
-	ov511->compress_inited = 1;
+	ov->compress_inited = 1;
 out:	
 	return rc;
 }
@@ -1719,22 +1705,22 @@
 
 /* Sets sensor's contrast setting to "val" */
 static int
-sensor_set_contrast(struct usb_ov511 *ov511, unsigned short val)
+sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
 {
 	int rc;
 
 	PDEBUG(3, "%d", val);
 
-	if (ov511->stop_during_set)
-		if (ov511_stop(ov511) < 0)
+	if (ov->stop_during_set)
+		if (ov51x_stop(ov) < 0)
 			return -EIO;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
 	case SEN_OV6630:
 	{
-		rc = ov51x_i2c_write(ov511, OV7610_REG_CNT, val >> 8);
+		rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
@@ -1747,14 +1733,14 @@
 		};
 
 		/* Use Y gamma control instead. Bit 0 enables it. */
-		rc = ov51x_i2c_write(ov511, 0x64, ctab[val>>12]);
+		rc = i2c_w(ov, 0x64, ctab[val>>12]);
 		if (rc < 0)
 			goto out;
 		break;
 	}
 	case SEN_SAA7111A:
 	{
-		rc = ov51x_i2c_write(ov511, 0x0b, val >> 9);
+		rc = i2c_w(ov, 0x0b, val >> 9);
 		if (rc < 0)
 			goto out;
 		break;
@@ -1768,9 +1754,9 @@
 	}
 
 	rc = 0;		/* Success */
-	ov511->contrast = val;
+	ov->contrast = val;
 out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -1778,15 +1764,15 @@
 
 /* Gets sensor's contrast setting */
 static int
-sensor_get_contrast(struct usb_ov511 *ov511, unsigned short *val)
+sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
 {
 	int rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_read(ov511, OV7610_REG_CNT);
+		rc = i2c_r(ov, OV7610_REG_CNT);
 		if (rc < 0)
 			return rc;
 		else
@@ -1794,14 +1780,14 @@
 		break;
 	case SEN_OV7620:
 		/* Use Y gamma reg instead. Bit 0 is the enable bit. */
-		rc = ov51x_i2c_read(ov511, 0x64);
+		rc = i2c_r(ov, 0x64);
 		if (rc < 0)
 			return rc;
 		else
 			*val = (rc & 0xfe) << 8;
 		break;
 	case SEN_SAA7111A:
-		*val = ov511->contrast;
+		*val = ov->contrast;
 		break;
 	default:
 		PDEBUG(3, "Unsupported with this sensor");
@@ -1809,7 +1795,7 @@
 	}
 
 	PDEBUG(3, "%d", *val);
-	ov511->contrast = *val;
+	ov->contrast = *val;
 
 	return 0;
 }
@@ -1818,35 +1804,35 @@
 
 /* Sets sensor's brightness setting to "val" */
 static int
-sensor_set_brightness(struct usb_ov511 *ov511, unsigned short val)
+sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
 {
 	int rc;
 
 	PDEBUG(4, "%d", val);
 
-	if (ov511->stop_during_set)
-		if (ov511_stop(ov511) < 0)
+	if (ov->stop_during_set)
+		if (ov51x_stop(ov) < 0)
 			return -EIO;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620AE:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8);
+		rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	case SEN_OV7620:
 		/* 7620 doesn't like manual changes when in auto mode */
-		if (!ov511->auto_brt) {
-			rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8);
+		if (!ov->auto_brt) {
+			rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
 			if (rc < 0)
 				goto out;
 		}
 		break;
 	case SEN_SAA7111A:
-		rc = ov51x_i2c_write(ov511, 0x0a, val >> 8);
+		rc = i2c_w(ov, 0x0a, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
@@ -1857,9 +1843,9 @@
 	}
 
 	rc = 0;		/* Success */
-	ov511->brightness = val;
+	ov->brightness = val;
 out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -1867,24 +1853,24 @@
 
 /* Gets sensor's brightness setting */
 static int
-sensor_get_brightness(struct usb_ov511 *ov511, unsigned short *val)
+sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
 {
 	int rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620AE:
 	case SEN_OV7620:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_read(ov511, OV7610_REG_BRT);
+		rc = i2c_r(ov, OV7610_REG_BRT);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
 	case SEN_SAA7111A:
-		*val = ov511->brightness;
+		*val = ov->brightness;
 		break;
 	default:
 		PDEBUG(3, "Unsupported with this sensor");
@@ -1892,7 +1878,7 @@
 	}
 
 	PDEBUG(3, "%d", *val);
-	ov511->brightness = *val;
+	ov->brightness = *val;
 
 	return 0;
 }
@@ -1901,36 +1887,36 @@
 
 /* Sets sensor's saturation (color intensity) setting to "val" */
 static int
-sensor_set_saturation(struct usb_ov511 *ov511, unsigned short val)
+sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
 {
 	int rc;
 
 	PDEBUG(3, "%d", val);
 
-	if (ov511->stop_during_set)
-		if (ov511_stop(ov511) < 0)
+	if (ov->stop_during_set)
+		if (ov51x_stop(ov) < 0)
 			return -EIO;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620AE:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8);
+		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	case SEN_OV7620:
 //		/* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-//		rc = ov511_i2c_write(ov511->dev, 0x62, (val >> 9) & 0x7e);
+//		rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
 //		if (rc < 0)
 //			goto out;
-		rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8);
+		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	case SEN_SAA7111A:
-		rc = ov51x_i2c_write(ov511, 0x0c, val >> 9);
+		rc = i2c_w(ov, 0x0c, val >> 9);
 		if (rc < 0)
 			goto out;
 		break;
@@ -1941,9 +1927,9 @@
 	}
 
 	rc = 0;		/* Success */
-	ov511->colour = val;
+	ov->colour = val;
 out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -1951,16 +1937,16 @@
 
 /* Gets sensor's saturation (color intensity) setting */
 static int
-sensor_get_saturation(struct usb_ov511 *ov511, unsigned short *val)
+sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
 {
 	int rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620AE:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_read(ov511, OV7610_REG_SAT);
+		rc = i2c_r(ov, OV7610_REG_SAT);
 		if (rc < 0)
 			return rc;
 		else
@@ -1968,19 +1954,19 @@
 		break;
 	case SEN_OV7620:
 //		/* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-//		rc = ov51x_i2c_read(ov511, 0x62);
+//		rc = i2c_r(ov, 0x62);
 //		if (rc < 0)
 //			return rc;
 //		else
 //			*val = (rc & 0x7e) << 9;
-		rc = ov51x_i2c_read(ov511, OV7610_REG_SAT);
+		rc = i2c_r(ov, OV7610_REG_SAT);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
 	case SEN_SAA7111A:
-		*val = ov511->colour;
+		*val = ov->colour;
 		break;
 	default:
 		PDEBUG(3, "Unsupported with this sensor");
@@ -1988,7 +1974,7 @@
 	}
 
 	PDEBUG(3, "%d", *val);
-	ov511->colour = *val;
+	ov->colour = *val;
 
 	return 0;
 }
@@ -1997,44 +1983,42 @@
 
 /* Sets sensor's hue (red/blue balance) setting to "val" */
 static int
-sensor_set_hue(struct usb_ov511 *ov511, unsigned short val)
+sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
 {
 	int rc;
 
 	PDEBUG(3, "%d", val);
 
-	if (ov511->stop_during_set)
-		if (ov511_stop(ov511) < 0)
+	if (ov->stop_during_set)
+		if (ov51x_stop(ov) < 0)
 			return -EIO;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_write(ov511, OV7610_REG_RED, 0xFF - (val >> 8));
+		rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
 		if (rc < 0)
 			goto out;
 
-		rc = ov51x_i2c_write(ov511, OV7610_REG_BLUE, val >> 8);
+		rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
 		if (rc < 0)
 			goto out;
 		break;
 	case SEN_OV7620:
 // Hue control is causing problems. I will enable it once it's fixed.
 #if 0
-		rc = ov51x_i2c_write(ov511, 0x7a,
-				     (unsigned char)(val >> 8) + 0xb);
+		rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
 		if (rc < 0)
 			goto out;
 
-		rc = ov51x_i2c_write(ov511, 0x79, 
-				     (unsigned char)(val >> 8) + 0xb);
+		rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
 		if (rc < 0)
 			goto out;
 #endif
 		break;
 	case SEN_SAA7111A:
-		rc = ov51x_i2c_write(ov511, 0x0d, (val + 32768) >> 8);
+		rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
 		if (rc < 0)
 			goto out;
 		break;
@@ -2045,9 +2029,9 @@
 	}
 
 	rc = 0;		/* Success */
-	ov511->hue = val;
+	ov->hue = val;
 out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -2055,29 +2039,29 @@
 
 /* Gets sensor's hue (red/blue balance) setting */
 static int
-sensor_get_hue(struct usb_ov511 *ov511, unsigned short *val)
+sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
 {
 	int rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = ov51x_i2c_read(ov511, OV7610_REG_BLUE);
+		rc = i2c_r(ov, OV7610_REG_BLUE);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
 	case SEN_OV7620:
-		rc = ov51x_i2c_read(ov511, 0x7a);
+		rc = i2c_r(ov, 0x7a);
 		if (rc < 0)
 			return rc;
 		else
 			*val = rc << 8;
 		break;
 	case SEN_SAA7111A:
-		*val = ov511->hue;
+		*val = ov->hue;
 		break;
 	default:
 		PDEBUG(3, "Unsupported with this sensor");
@@ -2085,7 +2069,7 @@
 	}
 
 	PDEBUG(3, "%d", *val);
-	ov511->hue = *val;
+	ov->hue = *val;
 
 	return 0;
 }
@@ -2093,30 +2077,30 @@
 /* -------------------------------------------------------------------------- */
 
 static inline int
-sensor_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
+sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
 {
 	int rc;
 
 	PDEBUG(4, "sensor_set_picture");
 
-	ov511->whiteness = p->whiteness;
+	ov->whiteness = p->whiteness;
 
 	/* Don't return error if a setting is unsupported, or rest of settings
          * will not be performed */
 
-	rc = sensor_set_contrast(ov511, p->contrast);
+	rc = sensor_set_contrast(ov, p->contrast);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_set_brightness(ov511, p->brightness);
+	rc = sensor_set_brightness(ov, p->brightness);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_set_saturation(ov511, p->colour);
+	rc = sensor_set_saturation(ov, p->colour);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_set_hue(ov511, p->hue);
+	rc = sensor_set_hue(ov, p->hue);
 	if (FATAL_ERROR(rc))
 		return rc;
 
@@ -2124,7 +2108,7 @@
 }
 
 static inline int
-sensor_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
+sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
 {
 	int rc;
 
@@ -2133,27 +2117,27 @@
 	/* Don't return error if a setting is unsupported, or rest of settings
          * will not be performed */
 
-	rc = sensor_get_contrast(ov511, &(p->contrast));
+	rc = sensor_get_contrast(ov, &(p->contrast));
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_get_brightness(ov511, &(p->brightness));
+	rc = sensor_get_brightness(ov, &(p->brightness));
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_get_saturation(ov511, &(p->colour));
+	rc = sensor_get_saturation(ov, &(p->colour));
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_get_hue(ov511, &(p->hue));
+	rc = sensor_get_hue(ov, &(p->hue));
 	if (FATAL_ERROR(rc))
 		return rc;
 
 	p->whiteness = 105 << 8;
 
 	/* Can we get these from frame[0]? -claudio? */
-	p->depth = ov511->frame[0].depth;
-	p->palette = ov511->frame[0].format;
+	p->depth = ov->frame[0].depth;
+	p->palette = ov->frame[0].format;
 
 	return 0;
 }
@@ -2162,24 +2146,24 @@
 /* Sets current exposure for sensor. This only has an effect if auto-exposure
  * is off */
 static inline int
-sensor_set_exposure(struct usb_ov511 *ov511, unsigned char val)
+sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
 {
 	int rc;
 
 	PDEBUG(3, "%d", val);
 
-	if (ov511->stop_during_set)
-		if (ov511_stop(ov511) < 0)
+	if (ov->stop_during_set)
+		if (ov51x_stop(ov) < 0)
 			return -EIO;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV6620:
 	case SEN_OV6630:
 	case SEN_OV7610:
 	case SEN_OV7620:
 	case SEN_OV7620AE:
 	case SEN_OV8600:
-		rc = ov51x_i2c_write(ov511, 0x10, val);
+		rc = i2c_w(ov, 0x10, val);
 		if (rc < 0)
 			goto out;
 
@@ -2195,9 +2179,9 @@
 	}
 
 	rc = 0;		/* Success */
-	ov511->exposure = val;
+	ov->exposure = val;
 out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -2206,18 +2190,18 @@
 /* Gets current exposure level from sensor, regardless of whether it is under
  * manual control. */
 static int
-sensor_get_exposure(struct usb_ov511 *ov511, unsigned char *val)
+sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
 {
 	int rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV6620:
 	case SEN_OV6630:
 	case SEN_OV7620:
 	case SEN_OV7620AE:
 	case SEN_OV8600:
-		rc = ov51x_i2c_read(ov511, 0x10);
+		rc = i2c_r(ov, 0x10);
 		if (rc < 0)
 			return rc;
 		else
@@ -2235,24 +2219,22 @@
 	}
 
 	PDEBUG(3, "%d", *val);
-	ov511->exposure = *val;
+	ov->exposure = *val;
 
 	return 0;
 }
 
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
 static inline void 
-ov51x_led_control(struct usb_ov511 *ov511, int enable)
+ov51x_led_control(struct usb_ov511 *ov, int enable)
 {
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	if (ov511->bridge == BRG_OV511PLUS)
-		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, 
-			        enable ? 1 : 0);
-	else if (ov511->bridge == BRG_OV518 ||
-		 ov511->bridge == BRG_OV518PLUS)
-		ov511_reg_write_mask(ov511->dev, OV518_REG_GPIO_OUT, 
-				     enable ? 0x02 : 0x00, 0x02);
+	if (ov->bridge == BRG_OV511PLUS)
+		reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
+	else if (ov->bclass == BCL_OV518)
+		reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
+
 	return;
 }
 
@@ -2266,7 +2248,7 @@
  * Returns: 0 for success
  */
 static int
-sensor_set_light_freq(struct usb_ov511 *ov511, int freq)
+sensor_set_light_freq(struct usb_ov511 *ov, int freq)
 {
 	int sixty;
 
@@ -2281,24 +2263,24 @@
 		return -EINVAL;
 	}
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
-		ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80);
-		ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac);
-		ov51x_i2c_write_mask(ov511, 0x13, 0x10, 0x10);
-		ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x10);
+		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+		i2c_w(ov, 0x2b, sixty?0x00:0xac);
+		i2c_w_mask(ov, 0x13, 0x10, 0x10);
+		i2c_w_mask(ov, 0x13, 0x00, 0x10);
 		break;
 	case SEN_OV7620:
 	case SEN_OV7620AE:
 	case SEN_OV8600:
-		ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80);
-		ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac);
-		ov51x_i2c_write_mask(ov511, 0x76, 0x01, 0x01);
+		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+		i2c_w(ov, 0x2b, sixty?0x00:0xac);
+		i2c_w_mask(ov, 0x76, 0x01, 0x01);
 		break;		
 	case SEN_OV6620:
 	case SEN_OV6630:
-		ov51x_i2c_write(ov511, 0x2b, sixty?0xa8:0x28);
-		ov51x_i2c_write(ov511, 0x2a, sixty?0x84:0xa4);
+		i2c_w(ov, 0x2b, sixty?0xa8:0x28);
+		i2c_w(ov, 0x2a, sixty?0x84:0xa4);
 		break;
 	case SEN_KS0127:
 	case SEN_KS0127B:
@@ -2310,7 +2292,7 @@
 		return -EINVAL;
 	}
 
-	ov511->lightfreq = freq;
+	ov->lightfreq = freq;
 
 	return 0;
 }
@@ -2325,23 +2307,23 @@
  * Returns: 0 for success
  */
 static inline int
-sensor_set_banding_filter(struct usb_ov511 *ov511, int enable)
+sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
 {
 	int rc;
 
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B
-		|| ov511->sensor == SEN_SAA7111A) {
+	if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+		|| ov->sensor == SEN_SAA7111A) {
 		PDEBUG(5, "Unsupported with this sensor");
 		return -EPERM;
 	}
 
-	rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x04:0x00, 0x04);
+	rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
 	if (rc < 0)
 		return rc;
 
-	ov511->bandfilt = enable;
+	ov->bandfilt = enable;
 
 	return 0;
 }
@@ -2353,23 +2335,23 @@
  * Returns: 0 for success
  */
 static inline int
-sensor_set_auto_brightness(struct usb_ov511 *ov511, int enable)
+sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
 {
 	int rc;
 
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B
-		|| ov511->sensor == SEN_SAA7111A) {
+	if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+		|| ov->sensor == SEN_SAA7111A) {
 		PDEBUG(5, "Unsupported with this sensor");
 		return -EPERM;
 	}
 
-	rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x10:0x00, 0x10);
+	rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
 	if (rc < 0)
 		return rc;
 
-	ov511->auto_brt = enable;
+	ov->auto_brt = enable;
 
 	return 0;
 }
@@ -2381,22 +2363,22 @@
  * Returns: 0 for success
  */
 static inline int
-sensor_set_auto_exposure(struct usb_ov511 *ov511, int enable)
+sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
 {	
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
-		ov51x_i2c_write_mask(ov511, 0x29, enable?0x00:0x80, 0x80);
+		i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
 		break;
 	case SEN_OV6620:
 	case SEN_OV7620:
 	case SEN_OV7620AE:
 	case SEN_OV8600:
-		ov51x_i2c_write_mask(ov511, 0x13, enable?0x01:0x00, 0x01);
+		i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
 		break;		
 	case SEN_OV6630:
-		ov51x_i2c_write_mask(ov511, 0x28, enable?0x00:0x10, 0x10);
+		i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
 		break;
 	case SEN_KS0127:
 	case SEN_KS0127B:
@@ -2408,7 +2390,7 @@
 		return -EINVAL;
 	}
 
-	ov511->auto_exp = enable;
+	ov->auto_exp = enable;
 
 	return 0;
 }
@@ -2421,27 +2403,27 @@
  * Returns: 0 for success
  */
 static int
-sensor_set_backlight(struct usb_ov511 *ov511, int enable)
+sensor_set_backlight(struct usb_ov511 *ov, int enable)
 {
 
 	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7620:
 	case SEN_OV8600:
-		ov51x_i2c_write_mask(ov511, 0x68, enable?0xe0:0xc0, 0xe0);
-		ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08);
-		ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02);
+		i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
+		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
 		break;		
 	case SEN_OV6620:
-		ov51x_i2c_write_mask(ov511, 0x4e, enable?0xe0:0xc0, 0xe0);
-		ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08);
-		ov51x_i2c_write_mask(ov511, 0x0e, enable?0x80:0x00, 0x80);
+		i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
+		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+		i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
 		break;
 	case SEN_OV6630:
-		ov51x_i2c_write_mask(ov511, 0x4e, enable?0x80:0x60, 0xe0);
-		ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08);
-		ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02);
+		i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
+		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
 		break;
 	case SEN_OV7610:
 	case SEN_OV7620AE:
@@ -2455,7 +2437,7 @@
 		return -EINVAL;
 	}
 
-	ov511->backlight = enable;
+	ov->backlight = enable;
 
 	return 0;
 }
@@ -2464,7 +2446,7 @@
  * planar or not), or zero for unsupported format.
  */
 static inline int 
-ov511_get_depth(int palette)
+get_depth(int palette)
 {
 	switch (palette) {
 	case VIDEO_PALETTE_GREY:    return 8;
@@ -2487,55 +2469,55 @@
 		return 0;
 	else
 		return ((frame->width * frame->height
-			 * ov511_get_depth(frame->format)) >> 3);
+			 * get_depth(frame->format)) >> 3);
 }
 
 static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov511, int width, int height,
+mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
 			 int mode, int sub_flag, int qvga)
 {
 	int clock;
 
 	/******** Mode (VGA/QVGA) and sensor specific regs ********/
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
-		ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04);
+		i2c_w(ov, 0x14, qvga?0x24:0x04);
 // FIXME: Does this improve the image quality or frame rate?
 #if 0
-		ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20);
-		ov51x_i2c_write(ov511, 0x24, 0x10);
-		ov51x_i2c_write(ov511, 0x25, qvga?0x40:0x8a);
-		ov51x_i2c_write(ov511, 0x2f, qvga?0x30:0xb0);
-		ov51x_i2c_write(ov511, 0x35, qvga?0x1c:0x9c);
+		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+		i2c_w(ov, 0x24, 0x10);
+		i2c_w(ov, 0x25, qvga?0x40:0x8a);
+		i2c_w(ov, 0x2f, qvga?0x30:0xb0);
+		i2c_w(ov, 0x35, qvga?0x1c:0x9c);
 #endif
 		break;
 	case SEN_OV7620:
-//		ov51x_i2c_write(ov511, 0x2b, 0x00);
-		ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84);
-		ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20);
-		ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a);
-		ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60);
-		ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40);
-		ov51x_i2c_write_mask(ov511, 0x67, qvga?0xf0:0x90, 0xf0);
-		ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20);
+//		i2c_w(ov, 0x2b, 0x00);
+		i2c_w(ov, 0x14, qvga?0xa4:0x84);
+		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+		i2c_w(ov, 0x24, qvga?0x20:0x3a);
+		i2c_w(ov, 0x25, qvga?0x30:0x60);
+		i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+		i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
+		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
 		break;
 	case SEN_OV7620AE:
-//		ov51x_i2c_write(ov511, 0x2b, 0x00);
-		ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84);
+//		i2c_w(ov, 0x2b, 0x00);
+		i2c_w(ov, 0x14, qvga?0xa4:0x84);
 // FIXME: Enable this once 7620AE uses 7620 initial settings
 #if 0
-		ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20);
-		ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a);
-		ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60);
-		ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40);
-		ov51x_i2c_write_mask(ov511, 0x67, qvga?0xb0:0x90, 0xf0);
-		ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20);
+		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+		i2c_w(ov, 0x24, qvga?0x20:0x3a);
+		i2c_w(ov, 0x25, qvga?0x30:0x60);
+		i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+		i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
+		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
 #endif
 		break;
 	case SEN_OV6620:
 	case SEN_OV6630:
-		ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04);
+		i2c_w(ov, 0x14, qvga?0x24:0x04);
 		/* No special settings yet */
 		break;
 	default:
@@ -2546,19 +2528,17 @@
 	/******** Palette-specific regs ********/
 
 	if (mode == VIDEO_PALETTE_GREY) {
-		if (ov511->sensor == SEN_OV7610
-		    || ov511->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
 			/* these aren't valid on the OV6620/OV7620/6630? */
-			ov51x_i2c_write_mask(ov511, 0x0e, 0x40, 0x40);
+			i2c_w_mask(ov, 0x0e, 0x40, 0x40);
 		}
-		ov51x_i2c_write_mask(ov511, 0x13, 0x20, 0x20);
+		i2c_w_mask(ov, 0x13, 0x20, 0x20);
 	} else {
-		if (ov511->sensor == SEN_OV7610
-		    || ov511->sensor == SEN_OV7620AE) {
+		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
 			/* not valid on the OV6620/OV7620/6630? */
-			ov51x_i2c_write_mask(ov511, 0x0e, 0x00, 0x40);
+			i2c_w_mask(ov, 0x0e, 0x00, 0x40);
 		}
-		ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x20);
+		i2c_w_mask(ov, 0x13, 0x00, 0x20);
 	}
 
 	/******** Clock programming ********/
@@ -2567,13 +2547,13 @@
 
 	/* The OV6620 needs special handling. This prevents the 
 	 * severe banding that normally occurs */
-	if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630)
+	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
 	{
 		/* Clock down */
 
-		ov51x_i2c_write(ov511, 0x2a, 0x04);
+		i2c_w(ov, 0x2a, 0x04);
 
-		if (ov511->compress) {
+		if (ov->compress) {
 //			clock = 0;    /* This ensures the highest frame rate */
 			clock = 3;
 		} else if (clockdiv == -1) {   /* If user didn't override it */
@@ -2584,21 +2564,21 @@
 
 		PDEBUG(4, "Setting clock divisor to %d", clock);
 
-		ov51x_i2c_write(ov511, 0x11, clock);
+		i2c_w(ov, 0x11, clock);
 
-		ov51x_i2c_write(ov511, 0x2a, 0x84);
+		i2c_w(ov, 0x2a, 0x84);
 		/* This next setting is critical. It seems to improve
 		 * the gain or the contrast. The "reserved" bits seem
 		 * to have some effect in this case. */
-		ov51x_i2c_write(ov511, 0x2d, 0x85);
+		i2c_w(ov, 0x2d, 0x85);
 	}
 	else
 	{
-		if (ov511->compress) {
+		if (ov->compress) {
 			clock = 1;    /* This ensures the highest frame rate */
 		} else if (clockdiv == -1) {   /* If user didn't override it */
 			/* Calculate and set the clock divisor */
-			clock = ((sub_flag ? ov511->subw * ov511->subh
+			clock = ((sub_flag ? ov->subw * ov->subh
 				  : width * height)
 				 * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
 				 / 66000;
@@ -2608,45 +2588,44 @@
 
 		PDEBUG(4, "Setting clock divisor to %d", clock);
 
-		ov51x_i2c_write(ov511, 0x11, clock);
+		i2c_w(ov, 0x11, clock);
 	}
 
 	/******** Special Features ********/
 
 	if (framedrop >= 0)
-		ov51x_i2c_write(ov511, 0x16, framedrop);
+		i2c_w(ov, 0x16, framedrop);
 
 	/* We only have code to convert GBR -> RGB24 */
 	if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
-		ov51x_i2c_write_mask(ov511, 0x12, 0x08, 0x08);
+		i2c_w_mask(ov, 0x12, 0x08, 0x08);
 	else
-		ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x08);
+		i2c_w_mask(ov, 0x12, 0x00, 0x08);
 
 	/* Test Pattern */
-	ov51x_i2c_write_mask(ov511, 0x12, (testpat?0x02:0x00), 0x02);
+	i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
 
 	/* Auto white balance */
 //	if (awb)
-		ov51x_i2c_write_mask(ov511, 0x12, 0x04, 0x04);
+		i2c_w_mask(ov, 0x12, 0x04, 0x04);
 //	else
-//		ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x04);
+//		i2c_w_mask(ov, 0x12, 0x00, 0x04);
 
-	// This will go away as soon as ov511_mode_init_sensor_regs()
+	// This will go away as soon as ov51x_mode_init_sensor_regs()
 	// is fully tested.
 	/* 7620/6620/6630? don't have register 0x35, so play it safe */
-	if (ov511->sensor == SEN_OV7610 ||
-	    ov511->sensor == SEN_OV7620AE) {
+	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) {
 		if (width == 640 && height == 480)
-			ov51x_i2c_write(ov511, 0x35, 0x9e);
+			i2c_w(ov, 0x35, 0x9e);
 		else
-			ov51x_i2c_write(ov511, 0x35, 0x1e);
+			i2c_w(ov, 0x35, 0x1e);
 	}
 
 	return 0;
 }
 
 static int
-set_ov_sensor_window(struct usb_ov511 *ov511, int width, int height, int mode,
+set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
 		     int sub_flag)
 {
 	int ret;
@@ -2655,7 +2634,7 @@
 
 	/* The different sensor ICs handle setting up of window differently.
 	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620AE:
 		hwsbase = 0x38;
@@ -2679,9 +2658,9 @@
 		return -EINVAL;
 	}
 
-	if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) {
+	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
 		if (width > 176 && height > 144) {  /* CIF */
-			ret = mode_init_ov_sensor_regs(ov511, width, height,
+			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 0);
 			if (ret < 0)
 				return ret;
@@ -2693,7 +2672,7 @@
 			err("Illegal dimensions");
 			return -EINVAL;
 		} else {			    /* QCIF */
-			ret = mode_init_ov_sensor_regs(ov511, width, height,
+			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 1);
 			if (ret < 0)
 				return ret;
@@ -2702,7 +2681,7 @@
 		}
 	} else {
 		if (width > 320 && height > 240) {  /* VGA */
-			ret = mode_init_ov_sensor_regs(ov511, width, height,
+			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 0);
 			if (ret < 0)
 				return ret;
@@ -2714,7 +2693,7 @@
 			err("Illegal dimensions");
 			return -EINVAL;
 		} else {			    /* QVGA */
-			ret = mode_init_ov_sensor_regs(ov511, width, height,
+			ret = mode_init_ov_sensor_regs(ov, width, height,
 				mode, sub_flag, 1);
 			if (ret < 0)
 				return ret;
@@ -2730,24 +2709,20 @@
 
 	/* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
 	if (sub_flag) {
-		ov51x_i2c_write(ov511, 0x17, hwsbase+(ov511->subx>>hwscale));
-		ov51x_i2c_write(ov511, 0x18,
-				hwebase+((ov511->subx+ov511->subw)>>hwscale));
-		ov51x_i2c_write(ov511, 0x19, vwsbase+(ov511->suby>>vwscale));
-		ov51x_i2c_write(ov511, 0x1a,
-				vwebase+((ov511->suby+ov511->subh)>>vwscale));
+		i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
+		i2c_w(ov, 0x18,	hwebase+((ov->subx+ov->subw)>>hwscale));
+		i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
+		i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
 	} else {
-		ov51x_i2c_write(ov511, 0x17, hwsbase + hoffset);
-		ov51x_i2c_write(ov511, 0x18,
-				hwebase + hoffset + (hwsize>>hwscale));
-		ov51x_i2c_write(ov511, 0x19, vwsbase + voffset);
-		ov51x_i2c_write(ov511, 0x1a,
-				vwebase + voffset + (vwsize>>vwscale));
+		i2c_w(ov, 0x17, hwsbase + hoffset);
+		i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
+		i2c_w(ov, 0x19, vwsbase + voffset);
+		i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
 	}
 
 #ifdef OV511_DEBUG
 	if (dump_sensor)
-		ov51x_dump_i2c_regs(ov511);
+		dump_i2c_regs(ov);
 #endif
 
 	return 0;
@@ -2758,18 +2733,14 @@
  * Do not put any sensor-specific code in here (including I2C I/O functions)
  */
 static int
-ov511_mode_init_regs(struct usb_ov511 *ov511,
+ov511_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
 	int lncnt, pxcnt, rc = 0;
-	struct usb_device *dev = ov511->dev;
-
-	if (!ov511 || !dev)
-		return -EFAULT;
 
 	if (sub_flag) {
-		width = ov511->subw;
-		height = ov511->subh;
+		width = ov->subw;
+		height = ov->subh;
 	}
 
 	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
@@ -2777,7 +2748,7 @@
 
 	// FIXME: This should be moved to a 7111a-specific function once
 	// subcapture is dealt with properly
-	if (ov511->sensor == SEN_SAA7111A) {
+	if (ov->sensor == SEN_SAA7111A) {
 		if (width == 320 && height == 240) {
 			/* No need to do anything special */
 		} else if (width == 640 && height == 480) {
@@ -2796,26 +2767,22 @@
 		return -EINVAL;
 	}
 
-	if (width < ov511->minwidth || height < ov511->minheight) {
+	if (width < ov->minwidth || height < ov->minheight) {
 		err("Requested dimensions are too small");
 		return -EINVAL;
 	}
 
-	if (ov511_stop(ov511) < 0)
+	if (ov51x_stop(ov) < 0)
 		return -EIO;
 
 	if (mode == VIDEO_PALETTE_GREY) {
-		ov511_reg_write(dev, 0x16, 0x00);
-
-		/* For snapshot */
-		ov511_reg_write(dev, 0x1e, 0x00);
-		ov511_reg_write(dev, 0x1f, 0x01);
+		reg_w(ov, R511_CAM_UV_EN, 0x00);
+		reg_w(ov, R511_SNAP_UV_EN, 0x00);
+		reg_w(ov, R511_SNAP_OPTS, 0x01);
 	} else {
-		ov511_reg_write(dev, 0x16, 0x01);
-
-		/* For snapshot */
-		ov511_reg_write(dev, 0x1e, 0x01);
-		ov511_reg_write(dev, 0x1f, 0x03);
+		reg_w(ov, R511_CAM_UV_EN, 0x01);
+		reg_w(ov, R511_SNAP_UV_EN, 0x01);
+		reg_w(ov, R511_SNAP_OPTS, 0x03);
 	}
 
 	/* Here I'm assuming that snapshot size == image size.
@@ -2824,25 +2791,28 @@
 	pxcnt = (width >> 3) - 1;
 	lncnt = (height >> 3) - 1;
 
-	ov511_reg_write(dev, 0x12, pxcnt);
-	ov511_reg_write(dev, 0x13, lncnt);
-	ov511_reg_write(dev, 0x14, 0x00);
-	ov511_reg_write(dev, 0x15, 0x00);
-	ov511_reg_write(dev, 0x18, 0x03);	/* YUV420, low pass filer on */
+	reg_w(ov, R511_CAM_PXCNT, pxcnt);
+	reg_w(ov, R511_CAM_LNCNT, lncnt);
+	reg_w(ov, R511_CAM_PXDIV, 0x00);
+	reg_w(ov, R511_CAM_LNDIV, 0x00);
+
+	/* YUV420, low pass filer on */
+	reg_w(ov, R511_CAM_OPTS, 0x03);
 
 	/* Snapshot additions */
-	ov511_reg_write(dev, 0x1a, pxcnt);
-	ov511_reg_write(dev, 0x1b, lncnt);
-        ov511_reg_write(dev, 0x1c, 0x00);
-        ov511_reg_write(dev, 0x1d, 0x00);
-
-	if (ov511->compress) {
-		ov511_reg_write(dev, 0x78, 0x07); // Turn on Y & UV compression
-		ov511_reg_write(dev, 0x79, 0x03); // Enable LUTs
-		ov511_reset(ov511, OV511_RESET_OMNICE);
+	reg_w(ov, R511_SNAP_PXCNT, pxcnt);
+	reg_w(ov, R511_SNAP_LNCNT, lncnt);
+	reg_w(ov, R511_SNAP_PXDIV, 0x00);
+	reg_w(ov, R511_SNAP_LNDIV, 0x00);
+
+	if (ov->compress) {
+		/* Enable Y and UV quantization and compression */
+		reg_w(ov, R511_COMP_EN, 0x07);
+		reg_w(ov, R511_COMP_LUT_EN, 0x03);
+		ov51x_reset(ov, OV511_RESET_OMNICE);
 	}
 //out:
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	return rc;
@@ -2866,17 +2836,15 @@
  * Do not put any sensor-specific code in here (including I2C I/O functions)
  */
 static int
-ov518_mode_init_regs(struct usb_ov511 *ov511,
+ov518_mode_init_regs(struct usb_ov511 *ov,
 		     int width, int height, int mode, int sub_flag)
 {
 	int i;
-	struct usb_device *dev = ov511->dev;
-	unsigned char b[3]; /* Multiple-value reg buffer */
 
 	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
 	       width, height, mode, sub_flag);
 
-	if (ov511_stop(ov511) < 0)
+	if (ov51x_stop(ov) < 0)
 		return -EIO;
 
 	for (i = 0; mlist518[i].width; i++) {
@@ -2894,113 +2862,94 @@
 //		pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
 //		lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
 //
-//		ov511_reg_write(dev, 0x12, pxcnt);
-//		ov511_reg_write(dev, 0x13, lncnt);
+//		reg_w(ov511, 0x12, pxcnt);
+//		reg_w(ov511, 0x13, lncnt);
 
 		/******** Set the mode ********/		
 
 		/* Mode independent regs */
-		ov511_reg_write(dev, 0x2b, 0x00);
-		ov511_reg_write(dev, 0x2d, 0x00);
-		ov511_reg_write(dev, 0x3b, 0x00);
-		ov511_reg_write(dev, 0x3d, 0x00);
+		reg_w(ov, 0x2b, 0x00);
+		reg_w(ov, 0x2d, 0x00);
+		reg_w(ov, 0x3b, 0x00);
+		reg_w(ov, 0x3d, 0x00);
 
 		/* Mode dependent regs. Regs 38 - 3e are always the same as
 		 * regs 28 - 2e */
-		ov511_reg_write_mask(dev, 0x28, mlist518[i].reg28
+		reg_w_mask(ov, 0x28, mlist518[i].reg28
 			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		ov511_reg_write(dev, 0x29, mlist518[i].reg29);
-		ov511_reg_write(dev, 0x2a, mlist518[i].reg2a);
-		ov511_reg_write(dev, 0x2c, mlist518[i].reg2c);
-		ov511_reg_write(dev, 0x2e, mlist518[i].reg2e);
-		ov511_reg_write_mask(dev, 0x38, mlist518[i].reg28 
+		reg_w(ov, 0x29, mlist518[i].reg29);
+		reg_w(ov, 0x2a, mlist518[i].reg2a);
+		reg_w(ov, 0x2c, mlist518[i].reg2c);
+		reg_w(ov, 0x2e, mlist518[i].reg2e);
+		reg_w_mask(ov, 0x38, mlist518[i].reg28 
 			| (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f);
-		ov511_reg_write(dev, 0x39, mlist518[i].reg29);
-		ov511_reg_write(dev, 0x3a, mlist518[i].reg2a);
-		ov511_reg_write(dev, 0x3c, mlist518[i].reg2c);
-		ov511_reg_write(dev, 0x3e, mlist518[i].reg2e);
-		ov511_reg_write(dev, 0x24, mlist518[i].reg24);
-		ov511_reg_write(dev, 0x25, mlist518[i].reg25);
+		reg_w(ov, 0x39, mlist518[i].reg29);
+		reg_w(ov, 0x3a, mlist518[i].reg2a);
+		reg_w(ov, 0x3c, mlist518[i].reg2c);
+		reg_w(ov, 0x3e, mlist518[i].reg2e);
+		reg_w(ov, 0x24, mlist518[i].reg24);
+		reg_w(ov, 0x25, mlist518[i].reg25);
 
 		/* Windows driver does this here; who knows why */
-		ov511_reg_write(dev, 0x2f, 0x80);
+		reg_w(ov, 0x2f, 0x80);
 
 		/******** Set the framerate (to 15 FPS) ********/		
 
 		/* Mode independent, but framerate dependent, regs */
 		/* These are for 15 FPS only */
-		ov511_reg_write(dev, 0x51, 0x08);
-		ov511_reg_write(dev, 0x22, 0x18);
-		ov511_reg_write(dev, 0x23, 0xff);
-		ov511_reg_write(dev, 0x71, 0x19);  /* Compression-related? */
+		reg_w(ov, 0x51, 0x08);
+		reg_w(ov, 0x22, 0x18);
+		reg_w(ov, 0x23, 0xff);
+		reg_w(ov, 0x71, 0x19);  /* Compression-related? */
 
 		// FIXME: Sensor-specific
 		/* Bit 5 is what matters here. Of course, it is "reserved" */
-		ov51x_i2c_write(ov511, 0x54, 0x23);
+		i2c_w(ov, 0x54, 0x23);
 
-		ov511_reg_write(dev, 0x2f, 0x80);
+		reg_w(ov, 0x2f, 0x80);
 
 		/* Mode dependent regs */
 		if ((width == 352 && height == 288) ||
 		    (width == 320 && height == 240)) {
-			b[0]=0x80; b[1]=0x02;
-			ov518_reg_write_multi(dev, 0x30, b, 2);
-			b[0]=0x90; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xc4, b, 2);
-			b[0]=0xf4; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xc6, b, 2);
-			b[0]=0xf4; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xc7, b, 2);
-			b[0]=0x8e; b[1]=0x00;
-			ov518_reg_write_multi(dev, 0xc8, b, 2);
-			b[0]=0x1a; b[1]=0x00; b[2]=0x02;
-			ov518_reg_write_multi(dev, 0xca, b, 3);
-			b[0]=0x14; b[1]=0x02;
-			ov518_reg_write_multi(dev, 0xcb, b, 2);
-			b[0]=0xd0; b[1]=0x07;
-			ov518_reg_write_multi(dev, 0xcc, b, 2);
-			b[0]=0x20; b[1]=0x00;
-			ov518_reg_write_multi(dev, 0xcd, b, 2);
-			b[0]=0x60; b[1]=0x02;
-			ov518_reg_write_multi(dev, 0xce, b, 2);
-
+			/*  640 (280h) byte iso packets */
+			ov518_reg_w32(ov, 0x30,    640, 2);	/* 280h   */
+			ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
+			ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
+			ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
+			ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
+			ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
+			ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
+			ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
+			ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
+			ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
 		} else if ((width == 176 && height == 144) ||
 			   (width == 160 && height == 120)) {
-			b[0]=0x80; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0x30, b, 2);
-			b[0]=0xc8; b[1]=0x00;
-			ov518_reg_write_multi(dev, 0xc4, b, 2);
-			b[0]=0x40; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xc6, b, 2);
-			b[0]=0x40; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xc7, b, 2);
-			b[0]=0x60; b[1]=0x00;
-			ov518_reg_write_multi(dev, 0xc8, b, 2);
-			b[0]=0x0f; b[1]=0x33; b[2]=0x01;
-			ov518_reg_write_multi(dev, 0xca, b, 3);
-			b[0]=0x40; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xcb, b, 2);
-			b[0]=0xec; b[1]=0x04;
-			ov518_reg_write_multi(dev, 0xcc, b, 2);
-			b[0]=0x13; b[1]=0x00;
-			ov518_reg_write_multi(dev, 0xcd, b, 2);
-			b[0]=0x6d; b[1]=0x01;
-			ov518_reg_write_multi(dev, 0xce, b, 2);
+			/*  384 (180h) byte iso packets */
+			ov518_reg_w32(ov, 0x30,    384, 2);	/* 180h   */
+			ov518_reg_w32(ov, 0xc4,    200, 2);	/* c8h    */
+			ov518_reg_w32(ov, 0xc6,    320, 2);	/* 140h   */
+			ov518_reg_w32(ov, 0xc7,    320, 2);	/* 140h   */
+			ov518_reg_w32(ov, 0xc8,     96, 2);	/* 60h    */
+			ov518_reg_w32(ov, 0xca,  78607, 3);	/* 1330fh */
+			ov518_reg_w32(ov, 0xcb,    320, 2);	/* 140h   */
+			ov518_reg_w32(ov, 0xcc,   1260, 2);	/* 4ech   */
+			ov518_reg_w32(ov, 0xcd,     19, 2);	/* 13h    */
+			ov518_reg_w32(ov, 0xce,    365, 2);	/* 16dh   */
 		} else {
 			/* Can't happen, since we already handled this case */
 			err("ov518_mode_init_regs(): **** logic error ****");
 		}
 
-		ov511_reg_write(dev, 0x2f, 0x80);
+		reg_w(ov, 0x2f, 0x80);
 
 		break;
 	}
 
-	if (ov511_restart(ov511) < 0)
+	if (ov51x_restart(ov) < 0)
 		return -EIO;
 
 	/* Reset it just for good measure */
-	if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0)
+	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
 		return -EIO;
 
 	if (mlist518[i].width == 0) {
@@ -3013,29 +2962,31 @@
 
 /* This is a wrapper around the OV511, OV518, and sensor specific functions */
 static int
-mode_init_regs(struct usb_ov511 *ov511,
+mode_init_regs(struct usb_ov511 *ov,
 	       int width, int height, int mode, int sub_flag)
 {
 	int rc = 0;
 
-	if (ov511->bridge == BRG_OV518 ||
-	    ov511->bridge == BRG_OV518PLUS) {
-		rc = ov518_mode_init_regs(ov511, width, height, mode, sub_flag);
+	if (!ov || !ov->dev)
+		return -EFAULT;
+
+	if (ov->bclass == BCL_OV518) {
+		rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
 	} else {
-		rc = ov511_mode_init_regs(ov511, width, height, mode, sub_flag);
+		rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
 	}
 
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_OV7610:
 	case SEN_OV7620:
 	case SEN_OV7620AE:
 	case SEN_OV8600:
 	case SEN_OV6620:
 	case SEN_OV6630:
-		rc = set_ov_sensor_window(ov511, width, height, mode, sub_flag);
+		rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
 		break;
 	case SEN_KS0127:
 	case SEN_KS0127B:
@@ -3043,10 +2994,10 @@
 		rc = -EINVAL;
 		break;
 	case SEN_SAA7111A:
-//		rc = mode_init_saa_sensor_regs(ov511, width, height, mode, 
+//		rc = mode_init_saa_sensor_regs(ov, width, height, mode, 
 //					       sub_flag);
 
-		PDEBUG(1, "SAA status = 0X%x", ov51x_i2c_read(ov511, 0x1f));
+		PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f));
 		break;
 	default:
 		err("Unknown sensor");
@@ -3057,25 +3008,25 @@
 		return rc;
 
 	/* Sensor-independent settings */
-	rc = sensor_set_auto_brightness(ov511, ov511->auto_brt);
+	rc = sensor_set_auto_brightness(ov, ov->auto_brt);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_set_auto_exposure(ov511, ov511->auto_exp);
+	rc = sensor_set_auto_exposure(ov, ov->auto_exp);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	rc = sensor_set_banding_filter(ov511, bandingfilter);
+	rc = sensor_set_banding_filter(ov, bandingfilter);
 	if (FATAL_ERROR(rc))
 		return rc;
 
-	if (ov511->lightfreq) {
-		rc = sensor_set_light_freq(ov511, lightfreq);
+	if (ov->lightfreq) {
+		rc = sensor_set_light_freq(ov, lightfreq);
 		if (FATAL_ERROR(rc))
 			return rc;
 	}
 
-	rc = sensor_set_backlight(ov511, ov511->backlight);
+	rc = sensor_set_backlight(ov, ov->backlight);
 	if (FATAL_ERROR(rc))
 		return rc;
 
@@ -3086,28 +3037,28 @@
  * useful for apps that use read() and do not set these.
  */
 static int 
-ov51x_set_default_params(struct usb_ov511 *ov511)
+ov51x_set_default_params(struct usb_ov511 *ov)
 {
 	int i;
 
-	PDEBUG(3, "%dx%d, RGB24", ov511->maxwidth, ov511->maxheight);
+	PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight);
 
 	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
 	 * (using read() instead). */
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov511->frame[i].width = ov511->maxwidth;
-		ov511->frame[i].height = ov511->maxheight;
-		ov511->frame[i].bytes_read = 0;
+		ov->frame[i].width = ov->maxwidth;
+		ov->frame[i].height = ov->maxheight;
+		ov->frame[i].bytes_read = 0;
 		if (force_palette)
-			ov511->frame[i].format = force_palette;
+			ov->frame[i].format = force_palette;
 		else
-			ov511->frame[i].format = VIDEO_PALETTE_RGB24;
-		ov511->frame[i].depth = ov511_get_depth(ov511->frame[i].format);
+			ov->frame[i].format = VIDEO_PALETTE_RGB24;
+		ov->frame[i].depth = get_depth(ov->frame[i].format);
 	}
 
 	/* Initialize to max width/height, RGB24 */
-	if (mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight,
-			   ov511->frame[0].format, 0) < 0)
+	if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
+			   ov->frame[0].format, 0) < 0)
 		return -EINVAL;
 
 	return 0;
@@ -3121,18 +3072,17 @@
 
 /* Set analog input port of decoder */
 static int 
-decoder_set_input(struct usb_ov511 *ov511, int input)
+decoder_set_input(struct usb_ov511 *ov, int input)
 {
 	PDEBUG(4, "port %d", input);
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_SAA7111A:
 	{
 		/* Select mode */
-		ov51x_i2c_write_mask(ov511, 0x02, input, 0x07);
+		i2c_w_mask(ov, 0x02, input, 0x07);
 		/* Bypass chrominance trap for modes 4..7 */
-		ov51x_i2c_write_mask(ov511, 0x09,
-				     (input > 3) ? 0x80:0x00, 0x80);
+		i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
 		break;
 	}
 	default:
@@ -3144,9 +3094,9 @@
 
 /* Get ASCII name of video input */
 static int 
-decoder_get_input_name(struct usb_ov511 *ov511, int input, char *name)
+decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
 {
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_SAA7111A:
 	{
 		if (input < 0 || input > 7)
@@ -3167,11 +3117,11 @@
 
 /* Set norm (NTSC, PAL, SECAM, AUTO) */
 static int 
-decoder_set_norm(struct usb_ov511 *ov511, int norm)
+decoder_set_norm(struct usb_ov511 *ov, int norm)
 {
 	PDEBUG(4, "%d", norm);
 
-	switch (ov511->sensor) {
+	switch (ov->sensor) {
 	case SEN_SAA7111A:
 	{
 		int reg_8, reg_e;
@@ -3192,8 +3142,8 @@
 			return -EINVAL;
 		}
 
-		ov51x_i2c_write_mask(ov511, 0x08, reg_8, 0xc0);
-		ov51x_i2c_write_mask(ov511, 0x0e, reg_e, 0x70);
+		i2c_w_mask(ov, 0x08, reg_8, 0xc0);
+		i2c_w_mask(ov, 0x0e, reg_e, 0x70);
 		break;
 	}
 	default:
@@ -3240,8 +3190,8 @@
 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
 
 static inline void
-ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
-		     int rowPixels, unsigned char * rgb, int bits)
+move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+	       int rowPixels, unsigned char * rgb, int bits)
 {
 	const int rvScale = 91881;
 	const int guScale = -22553;
@@ -3311,10 +3261,10 @@
  **********************************************************************/
 
 /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * array at pOut is specified by w.
+ * image at pOut is specified by w.
  */
 static inline void 
-ov511_make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
+make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
 {
 	unsigned char *pOut1 = pOut;
 	int x, y;
@@ -3352,7 +3302,7 @@
 	for (y = 0; y < frame->rawheight - 1; y += 8) {
 		pOut = pOutLine;
 		for (x = 0; x < frame->rawwidth - 1; x += 8) {
-			ov511_make_8x8(pIn, pOut, frame->rawwidth);
+			make_8x8(pIn, pOut, frame->rawwidth);
 			pIn += 64;
 			pOut += 8;
 		}
@@ -3411,8 +3361,8 @@
 	for (y = 0; y < frame->rawheight - 1; y += 16) {
 		pOut = pOutLine;
 		for (x = 0; x < frame->rawwidth - 1; x += 16) {
-			ov511_make_8x8(pIn, pOut, w);
-			ov511_make_8x8(pIn + 64, pOut + a/4, w);
+			make_8x8(pIn, pOut, w);
+			make_8x8(pIn + 64, pOut + a/4, w);
 			pIn += 384;
 			pOut += 8;
 		}
@@ -3426,7 +3376,7 @@
 	for (y = 0; y < frame->rawheight - 1; y += 8) {
 		pOut = pOutLine;
 		for (x = 0; x < frame->rawwidth - 1; x += 8) {
-			ov511_make_8x8(pIn, pOut, frame->rawwidth);
+			make_8x8(pIn, pOut, frame->rawwidth);
 			pIn += 64;
 			pOut += 8;
 			if ((++k) > 3) {
@@ -3483,17 +3433,17 @@
  *
  **********************************************************************/
 
-/* Chooses a decompression module, locks it, and sets ov511->decomp_ops
+/* Chooses a decompression module, locks it, and sets ov->decomp_ops
  * accordingly. Returns -ENXIO if decompressor is not available, otherwise
  * returns 0 if no other error.
  */
 static int 
-ov51x_request_decompressor(struct usb_ov511 *ov511)
+request_decompressor(struct usb_ov511 *ov)
 {
-	if (!ov511)
+	if (!ov)
 		return -ENODEV;
 
-	if (ov511->decomp_ops) {
+	if (ov->decomp_ops) {
 		err("ERROR: Decompressor already requested!");
 		return -EINVAL;
 	}
@@ -3501,24 +3451,23 @@
 	lock_kernel();
 
 	/* Try to get MMX, and fall back on no-MMX if necessary */
-	if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) {
+	if (ov->bclass == BCL_OV511) {
 		if (ov511_mmx_decomp_ops) {
 			PDEBUG(3, "Using OV511 MMX decompressor");
-			ov511->decomp_ops = ov511_mmx_decomp_ops;
+			ov->decomp_ops = ov511_mmx_decomp_ops;
 		} else if (ov511_decomp_ops) {
 			PDEBUG(3, "Using OV511 decompressor");
-			ov511->decomp_ops = ov511_decomp_ops;
+			ov->decomp_ops = ov511_decomp_ops;
 		} else {
 			err("No decompressor available");
 		}
-	} else if (ov511->bridge == BRG_OV518 ||
-		   ov511->bridge == BRG_OV518PLUS) {
+	} else if (ov->bclass == BCL_OV518) {
 		if (ov518_mmx_decomp_ops) {
 			PDEBUG(3, "Using OV518 MMX decompressor");
-			ov511->decomp_ops = ov518_mmx_decomp_ops;
+			ov->decomp_ops = ov518_mmx_decomp_ops;
 		} else if (ov518_decomp_ops) {
 			PDEBUG(3, "Using OV518 decompressor");
-			ov511->decomp_ops = ov518_decomp_ops;
+			ov->decomp_ops = ov518_decomp_ops;
 		} else {
 			err("No decompressor available");
 		}
@@ -3526,13 +3475,13 @@
 		err("Unknown bridge");
 	}
 
-	if (ov511->decomp_ops) {
-		if (!ov511->decomp_ops->decomp_lock) {
-			ov511->decomp_ops = NULL;
+	if (ov->decomp_ops) {
+		if (!ov->decomp_ops->decomp_lock) {
+			ov->decomp_ops = NULL;
 			unlock_kernel();
 			return -ENOSYS;
 		}
-		ov511->decomp_ops->decomp_lock();
+		ov->decomp_ops->decomp_lock();
 		unlock_kernel();
 		return 0;
 	} else {
@@ -3541,25 +3490,25 @@
 	}
 }
 
-/* Unlocks decompression module and nulls ov511->decomp_ops. Safe to call even
- * if ov511->decomp_ops is NULL.
+/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
+ * if ov->decomp_ops is NULL.
  */
 static void 
-ov51x_release_decompressor(struct usb_ov511 *ov511)
+release_decompressor(struct usb_ov511 *ov)
 {
 	int released = 0;	/* Did we actually do anything? */
 
-	if (!ov511)
+	if (!ov)
 		return;
 
 	lock_kernel();
 
-	if (ov511->decomp_ops && ov511->decomp_ops->decomp_unlock) {
-		ov511->decomp_ops->decomp_unlock();
+	if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) {
+		ov->decomp_ops->decomp_unlock();
 		released = 1;
 	}
 
-	ov511->decomp_ops = NULL;
+	ov->decomp_ops = NULL;
 	
 	unlock_kernel();
 
@@ -3568,26 +3517,26 @@
 }
 
 static void 
-ov51x_decompress(struct usb_ov511 *ov511, struct ov511_frame *frame,
-		 unsigned char *pIn0, unsigned char *pOut0)
+decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
+	   unsigned char *pIn0, unsigned char *pOut0)
 {
-	if (!ov511->decomp_ops)
-		if (ov51x_request_decompressor(ov511))
+	if (!ov->decomp_ops)
+		if (request_decompressor(ov))
 			return;
 
 	PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
 
 	if (frame->format == VIDEO_PALETTE_GREY 
-	    && ov511->decomp_ops->decomp_400) {
-		int ret = ov511->decomp_ops->decomp_400(
+	    && ov->decomp_ops->decomp_400) {
+		int ret = ov->decomp_ops->decomp_400(
 			pIn0,
 			pOut0,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
 		PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
-	} else if (ov511->decomp_ops->decomp_420) {
-		int ret = ov511->decomp_ops->decomp_420(
+	} else if (ov->decomp_ops->decomp_420) {
+		int ret = ov->decomp_ops->decomp_420(
 			pIn0,
 			pOut0,
 			frame->rawwidth,
@@ -3627,8 +3576,8 @@
 			u = (*pU++) - 128;
 			v = (*pV++) - 128;
 
-			ov511_move_420_block(y00, y01, y10, y11, u, v,
-					     frame->width, pOut, bits);
+			move_420_block(y00, y01, y10, y11, u, v,
+				       frame->width, pOut, bits);
 	
 			pY += 2;
 			pOut += 2 * bytes;
@@ -3783,11 +3732,11 @@
  * 	4. Fix the RGB offset, if necessary
  */
 static void 
-ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame)
+ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
 {
 	if (dumppix) {
 		memset(frame->data, 0, 
-			MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight));
+			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
 		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
 		memmove(frame->data, frame->rawdata, frame->bytes_recvd);
 		return;
@@ -3796,9 +3745,9 @@
 	/* YUV400 must be handled separately */
 	if (frame->format == VIDEO_PALETTE_GREY) {
 		/* Deinterlace frame, if necessary */
-		if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) {
+		if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
 			if (frame->compressed)
-				ov51x_decompress(ov511, frame, frame->rawdata,
+				decompress(ov, frame, frame->rawdata,
 						 frame->tempdata);
 			else
 				yuv400raw_to_yuv400p(frame, frame->rawdata,
@@ -3808,7 +3757,7 @@
 			            frame->data);
 		} else {
 			if (frame->compressed)
-				ov51x_decompress(ov511, frame, frame->rawdata,
+				decompress(ov, frame, frame->rawdata,
 						 frame->data);
 			else
 				yuv400raw_to_yuv400p(frame, frame->rawdata,
@@ -3820,12 +3769,12 @@
 
 	/* Process frame->data to frame->rawdata */
 	if (frame->compressed)
-		ov51x_decompress(ov511, frame, frame->rawdata, frame->tempdata);
+		decompress(ov, frame, frame->rawdata, frame->tempdata);
 	else
 		yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata);
 
 	/* Deinterlace frame, if necessary */
-	if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) {
+	if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
 		memmove(frame->rawdata, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		deinterlace(frame, RAWFMT_YUV420, frame->rawdata,
@@ -3879,7 +3828,7 @@
  **********************************************************************/
 
 static int 
-ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov511_move_data(struct usb_ov511 *ov, struct urb *urb)
 {
 	unsigned char *cdata;
 	int data_size, num, offset, i, totlen = 0;
@@ -3889,7 +3838,7 @@
 
 	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
 
-	data_size = ov511->packet_size - 1;
+	data_size = ov->packet_size - 1;
 
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int n = urb->iso_frame_desc[i].actual_length;
@@ -3900,15 +3849,15 @@
 
 		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 
-		aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
+		aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1;
 
-		if (!n || ov511->curframe == -1)
+		if (!n || ov->curframe == -1)
 			continue;
 
 		if (st)
 			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
 
-		frame = &ov511->frame[ov511->curframe];
+		frame = &ov->frame[ov->curframe];
 
 		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
 		 * byte non-zero. The EOF packet has image width/height in the
@@ -3926,7 +3875,7 @@
 
 		if (printph) {
 			info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[ov511->packet_size - 1],
+				cdata[ov->packet_size - 1],
 				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
 				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
 		}
@@ -3940,7 +3889,7 @@
 		/* Frame end */
 		if (cdata[8] & 0x80) {
 			ts = (struct timeval *)(frame->data 
-			      + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight));
+			      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
 			do_gettimeofday(ts);
 
 			/* Get the actual frame size from the EOF header */
@@ -3948,21 +3897,21 @@
 			frame->rawheight = ((int)(cdata[10]) + 1) * 8;
 
 	 		PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d",
-				ov511->curframe,
-				(int)(cdata[ov511->packet_size - 1]),
+				ov->curframe,
+				(int)(cdata[ov->packet_size - 1]),
 				frame->rawwidth,
 				frame->rawheight,
 				frame->bytes_recvd);
 
 			/* Validate the header data */
-			RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth);
-			RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight);
+			RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+			RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
 
 			/* Don't allow byte count to exceed buffer size */
 			RESTRICT_TO_RANGE(frame->bytes_recvd,
 					  8, 
-					  MAX_RAW_DATA_SIZE(ov511->maxwidth,
-					                    ov511->maxheight));
+					  MAX_RAW_DATA_SIZE(ov->maxwidth,
+					                    ov->maxheight));
 
 			if (frame->scanstate == STATE_LINES) {
 		    		int iFrameNext;
@@ -3976,20 +3925,20 @@
 
 				/* If next frame is ready or grabbing,
                                  * point to it */
-				iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES;
-				if (ov511->frame[iFrameNext].grabstate == FRAME_READY
-				    || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-					ov511->curframe = iFrameNext;
-					ov511->frame[iFrameNext].scanstate = STATE_SCANNING;
+				iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
+				if (ov->frame[iFrameNext].grabstate == FRAME_READY
+				    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
+					ov->curframe = iFrameNext;
+					ov->frame[iFrameNext].scanstate = STATE_SCANNING;
 				} else {
 					if (frame->grabstate == FRAME_DONE) {
 						PDEBUG(4, "Frame done! congratulations");
 					} else {
 						PDEBUG(4, "Frame not ready? state = %d",
-							ov511->frame[iFrameNext].grabstate);
+							ov->frame[iFrameNext].grabstate);
 					}
 
-					ov511->curframe = -1;
+					ov->curframe = -1;
 				}
 			} else {
 				PDEBUG(5, "Frame done, but not scanning");
@@ -3999,7 +3948,7 @@
 			 */
 		} else {
 			/* Frame start */
-			PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
+			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
 
 			/* Check to see if it's a snapshot frame */
 			/* FIXME?? Should the snapshot reset go here? Performance? */
@@ -4048,24 +3997,24 @@
 		/* Dump all data exactly as received */
 		if (dumppix == 2) {
 			frame->bytes_recvd += n - 1;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight))
+			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
 				memmove(frame->rawdata + frame->bytes_recvd - (n - 1),
 					&cdata[0], n - 1);
 			else
 				PDEBUG(3, "Raw data buffer overrun!! (%d)",
 					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov511->maxwidth,
-							    ov511->maxheight));
+					- MAX_RAW_DATA_SIZE(ov->maxwidth,
+							    ov->maxheight));
 		} else if (!frame->compressed && !remove_zeros) {
 			frame->bytes_recvd += num;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight))
+			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
 				memmove(frame->rawdata + frame->bytes_recvd - num,
 					&cdata[offset], num);
 			else
 				PDEBUG(3, "Raw data buffer overrun!! (%d)",
 					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov511->maxwidth,
-							    ov511->maxheight));
+					- MAX_RAW_DATA_SIZE(ov->maxwidth,
+							    ov->maxheight));
 		} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
 			int b, in = 0, allzero, copied=0;
 			if (offset) {
@@ -4088,7 +4037,7 @@
 					/* Don't copy it */
 				} else {
 					if (frame->bytes_recvd + copied + 32
-					    <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) {
+					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
 						memmove(frame->rawdata + frame->bytes_recvd + copied,
 							&cdata[in], 32);
 						copied += 32;
@@ -4112,7 +4061,7 @@
 }
 
 static int 
-ov518_move_data(struct usb_ov511 *ov511, urb_t *urb)
+ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
 {
 	unsigned char *cdata;
 	int i, data_size, totlen = 0;
@@ -4122,7 +4071,7 @@
 	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
 
 	/* OV518(+) has no packet numbering */
-	data_size = ov511->packet_size;
+	data_size = ov->packet_size;
 
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int n = urb->iso_frame_desc[i].actual_length;
@@ -4138,7 +4087,7 @@
 			continue;
 		}
 
-		if (ov511->curframe == -1) {
+		if (ov->curframe == -1) {
 			PDEBUG(4, "No frame currently active");
 			continue;
 		}
@@ -4146,21 +4095,7 @@
 		if (st)
 			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
 
-		frame = &ov511->frame[ov511->curframe];
-
-#if 0
-		{
-			int d;
-			/* Print all data */
-			for (d = 0; d <= data_size - 16; d += 16) {
-				info("%4x: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", d,
-					cdata[d], cdata[d+1], cdata[d+2], cdata[d+3],
-					cdata[d+4], cdata[d+5], cdata[d+6], cdata[d+7],
-					cdata[d+8], cdata[d+9], cdata[d+10], cdata[d+11],
-					cdata[d+12], cdata[d+13], cdata[d+14], cdata[d+15]);
-			}
-		}
-#endif
+		frame = &ov->frame[ov->curframe];
 
 		if (printph) {
 			info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
@@ -4178,7 +4113,7 @@
 				goto eof;
 			} else { //scanstate == STATE_SCANNING
 				/* Frame start */
-				PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
+				PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
 				goto sof;
 			}
 		} else {
@@ -4187,11 +4122,11 @@
 	
 eof:
 		ts = (struct timeval *)(frame->data
-		      + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight));
+		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
 		do_gettimeofday(ts);
 
  		PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-			ov511->curframe,
+			ov->curframe,
 			(int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd);
 
 		// FIXME: Since we don't know the header formats yet,
@@ -4200,13 +4135,13 @@
 		frame->rawheight = frame->height;
 
 		/* Validate the header data */
-		RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth);
-		RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight);
+		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
 
 		/* Don't allow byte count to exceed buffer size */
 		RESTRICT_TO_RANGE(frame->bytes_recvd,
 				  8, 
-				  MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight));
+				  MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight));
 
 		if (frame->scanstate == STATE_LINES) {
 	    		int iFrameNext;
@@ -4220,21 +4155,21 @@
 
 			/* If next frame is ready or grabbing,
 			 * point to it */
-			iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES;
-			if (ov511->frame[iFrameNext].grabstate == FRAME_READY
-			    || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-				ov511->curframe = iFrameNext;
-				ov511->frame[iFrameNext].scanstate = STATE_SCANNING;
-				frame = &ov511->frame[iFrameNext];
+			iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
+			if (ov->frame[iFrameNext].grabstate == FRAME_READY
+			    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
+				ov->curframe = iFrameNext;
+				ov->frame[iFrameNext].scanstate = STATE_SCANNING;
+				frame = &ov->frame[iFrameNext];
 			} else {
 				if (frame->grabstate == FRAME_DONE) {
 					PDEBUG(4, "Frame done! congratulations");
 				} else {
 					PDEBUG(4, "Frame not ready? state = %d",
-						ov511->frame[iFrameNext].grabstate);
+						ov->frame[iFrameNext].grabstate);
 				}
 
-				ov511->curframe = -1;
+				ov->curframe = -1;
 				PDEBUG(4, "SOF dropped (no active frame)");
 				continue;  /* Nowhere to store this frame */
 			}
@@ -4267,31 +4202,26 @@
 		/* Dump all data exactly as received */
 		if (dumppix == 2) {
 			frame->bytes_recvd += n;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight))
+			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
 				memmove(frame->rawdata + frame->bytes_recvd - n,
 					&cdata[0], n);
 			else
 				PDEBUG(3, "Raw data buffer overrun!! (%d)",
 					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov511->maxwidth,
-							    ov511->maxheight));
+					- MAX_RAW_DATA_SIZE(ov->maxwidth,
+							    ov->maxheight));
 		} else {
 			/* All incoming data are divided into 8-byte segments. If the
 			 * segment contains all zero bytes, it must be skipped. These
 			 * zero-segments allow the OV518 to mainain a constant data rate
 			 * regardless of the effectiveness of the compression. Segments
 			 * are aligned relative to the beginning of each isochronous
-			 * packet. The first segment is a header.
+			 * packet. The first segment is a header (the decompressor
+			 * skips it later).
 			 */
 
 			int b, in = 0, allzero, copied=0;
 
-// Decompressor expects the header
-#if 0
-			if (frame->bytes_recvd == 0)
-				in += 8;  /* Skip header */
-#endif
-
 			while (in < n) {
 				allzero = 1;
 				for (b = 0; b < 8; b++) {
@@ -4305,7 +4235,7 @@
 				/* Don't copy it */
 				} else {
 					if (frame->bytes_recvd + copied + 8
-					    <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) {
+					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
 						memmove(frame->rawdata + frame->bytes_recvd + copied,
 							&cdata[in], 8);
 						copied += 8;
@@ -4323,43 +4253,41 @@
 }
 
 static void 
-ov511_isoc_irq(struct urb *urb)
+ov51x_isoc_irq(struct urb *urb)
 {
 	int len;
-	struct usb_ov511 *ov511;
+	struct usb_ov511 *ov;
 
 	if (!urb->context) {
 		PDEBUG(4, "no context");
 		return;
 	}
 
-	ov511 = (struct usb_ov511 *) urb->context;
+	ov = (struct usb_ov511 *) urb->context;
 
-	if (!ov511->dev || !ov511->user) {
+	if (!ov || !ov->dev || !ov->user) {
 		PDEBUG(4, "no device, or not open");
 		return;
 	}
 
-	if (!ov511->streaming) {
+	if (!ov->streaming) {
 		PDEBUG(4, "hmmm... not streaming, but got interrupt");
 		return;
 	}
 
 	/* Copy the data received into our frame buffer */
-	if (ov511->curframe >= 0) {
-		if (ov511->bridge == BRG_OV511 || 
-		    ov511->bridge == BRG_OV511PLUS)
-			len = ov511_move_data(ov511, urb);
-		else if (ov511->bridge == BRG_OV518 ||
-			 ov511->bridge == BRG_OV518PLUS)
-			len = ov518_move_data(ov511, urb);
+	if (ov->curframe >= 0) {
+		if (ov->bclass == BCL_OV511)
+			len = ov511_move_data(ov, urb);
+		else if (ov->bclass == BCL_OV518)
+			len = ov518_move_data(ov, urb);
 		else
-			err("Unknown bridge device (%d)", ov511->bridge);
-	} else if (waitqueue_active(&ov511->wq)) {
-		wake_up_interruptible(&ov511->wq);
+			err("Unknown bridge device (%d)", ov->bridge);
+	} else if (waitqueue_active(&ov->wq)) {
+		wake_up_interruptible(&ov->wq);
 	}
 
-	urb->dev = ov511->dev;
+	urb->dev = ov->dev;
 
 	return;
 }
@@ -4371,16 +4299,16 @@
  ***************************************************************************/
 
 static int 
-ov511_init_isoc(struct usb_ov511 *ov511)
+ov51x_init_isoc(struct usb_ov511 *ov)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int fx, err, n, size;
 
 	PDEBUG(3, "*** Initializing capture ***");
 
-	ov511->curframe = -1;
+	ov->curframe = -1;
 
-	if (ov511->bridge == BRG_OV511) {
+	if (ov->bridge == BRG_OV511) {
 		if (cams == 1)				size = 993;
 		else if (cams == 2)			size = 513;
 		else if (cams == 3 || cams == 4)	size = 257;
@@ -4388,7 +4316,7 @@
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
-	} else if (ov511->bridge == BRG_OV511PLUS) {
+	} else if (ov->bridge == BRG_OV511PLUS) {
 		if (cams == 1)				size = 961;
 		else if (cams == 2)			size = 513;
 		else if (cams == 3 || cams == 4)	size = 257;
@@ -4398,8 +4326,7 @@
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
-	} else if (ov511->bridge == BRG_OV518 ||
-		   ov511->bridge == BRG_OV518PLUS) {
+	} else if (ov->bclass == BCL_OV518) {
 		if (cams == 1)				size = 896;
 		else if (cams == 2)			size = 512;
 		else if (cams == 3 || cams == 4)	size = 256;
@@ -4415,14 +4342,13 @@
 
 	if (packetsize == -1) {
 		// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-		if (ov511->bridge == BRG_OV518 ||
-		    ov511->bridge == BRG_OV518PLUS)
-			ov511_set_packet_size(ov511, 640);
+		if (ov->bclass == BCL_OV518)
+			ov51x_set_packet_size(ov, 640);
 		else
-			ov511_set_packet_size(ov511, size);
+			ov51x_set_packet_size(ov, size);
 	} else {
 			info("Forcing packet size to %d", packetsize);
-			ov511_set_packet_size(ov511, packetsize);
+			ov51x_set_packet_size(ov, packetsize);
 	}
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
@@ -4432,32 +4358,30 @@
 			err("init isoc: usb_alloc_urb ret. NULL");
 			return -ENOMEM;
 		}
-		ov511->sbuf[n].urb = urb;
-		urb->dev = ov511->dev;
-		urb->context = ov511;
-		urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
+		ov->sbuf[n].urb = urb;
+		urb->dev = ov->dev;
+		urb->context = ov;
+		urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
 		urb->transfer_flags = USB_ISO_ASAP;
-		urb->transfer_buffer = ov511->sbuf[n].data;
-		urb->complete = ov511_isoc_irq;
+		urb->transfer_buffer = ov->sbuf[n].data;
+		urb->complete = ov51x_isoc_irq;
 		urb->number_of_packets = FRAMES_PER_DESC;
-		urb->transfer_buffer_length =
-		 ov511->packet_size * FRAMES_PER_DESC;
+		urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
 		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-			urb->iso_frame_desc[fx].offset = 
-			 ov511->packet_size * fx;
-			urb->iso_frame_desc[fx].length = ov511->packet_size;
+			urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
+			urb->iso_frame_desc[fx].length = ov->packet_size;
 		}
 	}
 
-	ov511->streaming = 1;
+	ov->streaming = 1;
 
-	ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb;
+	ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb;
 	for (n = 0; n < OV511_NUMSBUF - 1; n++)
-		ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb;
+		ov->sbuf[n].urb->next = ov->sbuf[n+1].urb;
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
-		ov511->sbuf[n].urb->dev = ov511->dev;
-		err = usb_submit_urb(ov511->sbuf[n].urb);
+		ov->sbuf[n].urb->dev = ov->dev;
+		err = usb_submit_urb(ov->sbuf[n].urb);
 		if (err)
 			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
 	}
@@ -4466,51 +4390,51 @@
 }
 
 static void 
-ov511_stop_isoc(struct usb_ov511 *ov511)
+ov51x_stop_isoc(struct usb_ov511 *ov)
 {
 	int n;
 
-	if (!ov511->streaming || !ov511->dev)
+	if (!ov->streaming || !ov->dev)
 		return;
 
 	PDEBUG(3, "*** Stopping capture ***");
 
-	ov511_set_packet_size(ov511, 0);
+	ov51x_set_packet_size(ov, 0);
 
-	ov511->streaming = 0;
+	ov->streaming = 0;
 
 	/* Unschedule all of the iso td's */
 	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov511->sbuf[n].urb) {
-			ov511->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov511->sbuf[n].urb);
-			usb_free_urb(ov511->sbuf[n].urb);
-			ov511->sbuf[n].urb = NULL;
+		if (ov->sbuf[n].urb) {
+			ov->sbuf[n].urb->next = NULL;
+			usb_unlink_urb(ov->sbuf[n].urb);
+			usb_free_urb(ov->sbuf[n].urb);
+			ov->sbuf[n].urb = NULL;
 		}
 	}
 }
 
 static int 
-ov511_new_frame(struct usb_ov511 *ov511, int framenum)
+ov51x_new_frame(struct usb_ov511 *ov, int framenum)
 {
 	struct ov511_frame *frame;
 	int newnum;
 
-	PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe,
-		framenum);
-	if (!ov511->dev)
+	PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
+
+	if (!ov->dev)
 		return -1;
 
 	/* If we're not grabbing a frame right now and the other frame is */
 	/* ready to be grabbed into, then use it instead */
-	if (ov511->curframe == -1) {
+	if (ov->curframe == -1) {
 		newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
-		if (ov511->frame[newnum].grabstate == FRAME_READY)
+		if (ov->frame[newnum].grabstate == FRAME_READY)
 			framenum = newnum;
 	} else
 		return 0;
 
-	frame = &ov511->frame[framenum];
+	frame = &ov->frame[framenum];
 
 	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, 
 	       frame->width, frame->height);
@@ -4519,16 +4443,16 @@
 	frame->scanstate = STATE_SCANNING;
 	frame->snapshot = 0;
 
-	ov511->curframe = framenum;
+	ov->curframe = framenum;
 
 	/* Make sure it's not too big */
-	if (frame->width > ov511->maxwidth)
-		frame->width = ov511->maxwidth;
+	if (frame->width > ov->maxwidth)
+		frame->width = ov->maxwidth;
 
 	frame->width &= ~7L;		/* Multiple of 8 */
 
-	if (frame->height > ov511->maxheight)
-		frame->height = ov511->maxheight;
+	if (frame->height > ov->maxheight)
+		frame->height = ov->maxheight;
 
 	frame->height &= ~3L;		/* Multiple of 4 */
 
@@ -4540,84 +4464,86 @@
  * Buffer management
  *
  ***************************************************************************/
+
 static int 
-ov511_alloc(struct usb_ov511 *ov511)
+ov51x_alloc(struct usb_ov511 *ov)
 {
 	int i;
-	int w = ov511->maxwidth;
-	int h = ov511->maxheight;
+	const int w = ov->maxwidth;
+	const int h = ov->maxheight;
+	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
+	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 
 	PDEBUG(4, "entered");
-	down(&ov511->buf_lock);
+	down(&ov->buf_lock);
 
-	if (ov511->buf_state == BUF_PEND_DEALLOC) {
-		ov511->buf_state = BUF_ALLOCATED;
-		del_timer(&ov511->buf_timer);
+	if (ov->buf_state == BUF_PEND_DEALLOC) {
+		ov->buf_state = BUF_ALLOCATED;
+		del_timer(&ov->buf_timer);
 	}
 
-	if (ov511->buf_state == BUF_ALLOCATED)
+	if (ov->buf_state == BUF_ALLOCATED)
 		goto out;
 
-	ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE(w, h));
-	if (!ov511->fbuf)
+	ov->fbuf = rvmalloc(data_bufsize);
+	if (!ov->fbuf)
 		goto error;
 
-	ov511->rawfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h));
-	if (!ov511->rawfbuf) {
-		rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h));
-		ov511->fbuf = NULL;
+	ov->rawfbuf = vmalloc(raw_bufsize);
+	if (!ov->rawfbuf) {
+		rvfree(ov->fbuf, data_bufsize);
+		ov->fbuf = NULL;
 		goto error;
 	}
-	memset(ov511->rawfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h));
+	memset(ov->rawfbuf, 0, raw_bufsize);
 
-	ov511->tempfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h));
-	if (!ov511->tempfbuf) {
-		vfree(ov511->rawfbuf);
-		ov511->rawfbuf = NULL;
-		rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h));
-		ov511->fbuf = NULL;
+	ov->tempfbuf = vmalloc(raw_bufsize);
+	if (!ov->tempfbuf) {
+		vfree(ov->rawfbuf);
+		ov->rawfbuf = NULL;
+		rvfree(ov->fbuf, data_bufsize);
+		ov->fbuf = NULL;
 		goto error;
 	}
-	memset(ov511->tempfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h));
+	memset(ov->tempfbuf, 0, raw_bufsize);
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
-		ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
 			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-		if (!ov511->sbuf[i].data) {
+		if (!ov->sbuf[i].data) {
 			while (--i) {
-				kfree(ov511->sbuf[i].data);
-				ov511->sbuf[i].data = NULL;
+				kfree(ov->sbuf[i].data);
+				ov->sbuf[i].data = NULL;
 			}
-			vfree(ov511->tempfbuf);
-			ov511->tempfbuf = NULL;
-			vfree(ov511->rawfbuf);
-			ov511->rawfbuf = NULL;
-			rvfree(ov511->fbuf,
-			       OV511_NUMFRAMES * MAX_DATA_SIZE(w, h));
-			ov511->fbuf = NULL;
+			vfree(ov->tempfbuf);
+			ov->tempfbuf = NULL;
+			vfree(ov->rawfbuf);
+			ov->rawfbuf = NULL;
+			rvfree(ov->fbuf, data_bufsize);
+			ov->fbuf = NULL;
 
 			goto error;
 		}
-		PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);
+		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE(w, h);
-		ov511->frame[i].rawdata = ov511->rawfbuf 
+		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
+		ov->frame[i].rawdata = ov->rawfbuf 
 		 + i * MAX_RAW_DATA_SIZE(w, h);
-		ov511->frame[i].tempdata = ov511->tempfbuf 
+		ov->frame[i].tempdata = ov->tempfbuf 
 		 + i * MAX_RAW_DATA_SIZE(w, h);
-		PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data);
+		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
 	}
 
-	ov511->buf_state = BUF_ALLOCATED;
+	ov->buf_state = BUF_ALLOCATED;
 out:
-	up(&ov511->buf_lock);
+	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 	return 0;
 error:
-	ov511->buf_state = BUF_NOT_ALLOCATED;
-	up(&ov511->buf_lock);
+	ov->buf_state = BUF_NOT_ALLOCATED;
+	up(&ov->buf_lock);
 	PDEBUG(4, "errored");
 	return -ENOMEM;
 }
@@ -4628,206 +4554,212 @@
  *   them if you explicitly free them somewhere else!
  */
 static void 
-ov511_do_dealloc(struct usb_ov511 *ov511)
+ov51x_do_dealloc(struct usb_ov511 *ov)
 {
 	int i;
 	PDEBUG(4, "entered");
 
-	if (ov511->fbuf) {
-		rvfree(ov511->fbuf, OV511_NUMFRAMES
-		       * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight));
-		ov511->fbuf = NULL;
+	if (ov->fbuf) {
+		rvfree(ov->fbuf, OV511_NUMFRAMES
+		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		ov->fbuf = NULL;
 	}
 
-	if (ov511->rawfbuf) {
-		vfree(ov511->rawfbuf);
-		ov511->rawfbuf = NULL;
+	if (ov->rawfbuf) {
+		vfree(ov->rawfbuf);
+		ov->rawfbuf = NULL;
 	}
 
-	if (ov511->tempfbuf) {
-		vfree(ov511->tempfbuf);
-		ov511->tempfbuf = NULL;
+	if (ov->tempfbuf) {
+		vfree(ov->tempfbuf);
+		ov->tempfbuf = NULL;
 	}
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
-		if (ov511->sbuf[i].data) {
-			kfree(ov511->sbuf[i].data);
-			ov511->sbuf[i].data = NULL;
+		if (ov->sbuf[i].data) {
+			kfree(ov->sbuf[i].data);
+			ov->sbuf[i].data = NULL;
 		}
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov511->frame[i].data = NULL;
-		ov511->frame[i].rawdata = NULL;
-		ov511->frame[i].tempdata = NULL;
+		ov->frame[i].data = NULL;
+		ov->frame[i].rawdata = NULL;
+		ov->frame[i].tempdata = NULL;
 	}
 
 	PDEBUG(4, "buffer memory deallocated");
-	ov511->buf_state = BUF_NOT_ALLOCATED;
+	ov->buf_state = BUF_NOT_ALLOCATED;
 	PDEBUG(4, "leaving");
 }
 
 static void 
-ov511_buf_callback(unsigned long data)
+ov51x_buf_callback(unsigned long data)
 {
-	struct usb_ov511 *ov511 = (struct usb_ov511 *)data;
+	struct usb_ov511 *ov = (struct usb_ov511 *)data;
 	PDEBUG(4, "entered");
-	down(&ov511->buf_lock);
+	down(&ov->buf_lock);
 
-	if (ov511->buf_state == BUF_PEND_DEALLOC)
-		ov511_do_dealloc(ov511);
+	if (ov->buf_state == BUF_PEND_DEALLOC)
+		ov51x_do_dealloc(ov);
 
-	up(&ov511->buf_lock);
+	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
 
 static void 
-ov511_dealloc(struct usb_ov511 *ov511, int now)
+ov51x_dealloc(struct usb_ov511 *ov, int now)
 {
-	struct timer_list *bt = &(ov511->buf_timer);
+	struct timer_list *bt = &(ov->buf_timer);
 	PDEBUG(4, "entered");
-	down(&ov511->buf_lock);
+	down(&ov->buf_lock);
 
 	PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later");
 
-	if (ov511->buf_state == BUF_PEND_DEALLOC) {
-		ov511->buf_state = BUF_ALLOCATED;
+	if (ov->buf_state == BUF_PEND_DEALLOC) {
+		ov->buf_state = BUF_ALLOCATED;
 		del_timer(bt);
 	}
 
 	if (now)
-		ov511_do_dealloc(ov511);
+		ov51x_do_dealloc(ov);
 	else {
-		ov511->buf_state = BUF_PEND_DEALLOC;
+		ov->buf_state = BUF_PEND_DEALLOC;
 		init_timer(bt);
-		bt->function = ov511_buf_callback;
-		bt->data = (unsigned long)ov511;
+		bt->function = ov51x_buf_callback;
+		bt->data = (unsigned long)ov;
 		bt->expires = jiffies + buf_timeout * HZ;
 		add_timer(bt);
 	}
-	up(&ov511->buf_lock);
+	up(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
 
 /****************************************************************************
  *
- * V4L API
+ * V4L 1 API
  *
  ***************************************************************************/
 
 static int 
-ov511_open(struct video_device *vdev, int flags)
+ov51x_v4l1_open(struct video_device *vdev, int flags)
 {
-	struct usb_ov511 *ov511 = vdev->priv;
+	struct usb_ov511 *ov = vdev->priv;
 	int err, i;
 
 	PDEBUG(4, "opening");
 
-	down(&ov511->lock);
+	down(&ov->lock);
 
 	err = -EBUSY;
-	if (ov511->user) 
+	if (ov->user) 
 		goto out;
 
 	err = -ENOMEM;
-	if (ov511_alloc(ov511))
+	if (ov51x_alloc(ov))
 		goto out;
 
-	ov511->sub_flag = 0;
+	ov->sub_flag = 0;
 
 	/* In case app doesn't set them... */
-	if (ov51x_set_default_params(ov511) < 0)
+	if (ov51x_set_default_params(ov) < 0)
 		goto out;
 
 	/* Make sure frames are reset */
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov511->frame[i].grabstate = FRAME_UNUSED;
-		ov511->frame[i].bytes_read = 0;
+		ov->frame[i].grabstate = FRAME_UNUSED;
+		ov->frame[i].bytes_read = 0;
 	}
 
 	/* If compression is on, make sure now that a 
 	 * decompressor can be loaded */
-	if (ov511->compress && !ov511->decomp_ops) {
-		err = ov51x_request_decompressor(ov511);
-		if (err)
+	if (ov->compress && !ov->decomp_ops) {
+		err = request_decompressor(ov);
+		if (err && !dumppix)
 			goto out;
 	}
 
-	err = ov511_init_isoc(ov511);
+	err = ov51x_init_isoc(ov);
 	if (err) {
-		ov511_dealloc(ov511, 0);
+		ov51x_dealloc(ov, 0);
 		goto out;
 	}
 
-	ov511->user++;
+	ov->user++;
 	
-	if (ov511->led_policy == LED_AUTO)
-		ov51x_led_control(ov511, 1);
+	if (ov->led_policy == LED_AUTO)
+		ov51x_led_control(ov, 1);
 
 out:
-	up(&ov511->lock);
+	up(&ov->lock);
 
 	return err;
 }
 
 static void 
-ov511_close(struct video_device *dev)
+ov51x_v4l1_close(struct video_device *vdev)
 {
-	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
 	
-	down(&ov511->lock);
+	down(&ov->lock);
 
-	ov511->user--;
-	ov511_stop_isoc(ov511);
+	ov->user--;
+	ov51x_stop_isoc(ov);
 
-	ov51x_release_decompressor(ov511);
+	release_decompressor(ov);
 
-	if (ov511->led_policy == LED_AUTO)
-		ov51x_led_control(ov511, 0);
+	if (ov->led_policy == LED_AUTO)
+		ov51x_led_control(ov, 0);
 
-	if (ov511->dev)
-		ov511_dealloc(ov511, 0);
+	if (ov->dev)
+		ov51x_dealloc(ov, 0);
 
-	up(&ov511->lock);
+	up(&ov->lock);
 
 	/* Device unplugged while open. Only a minimum of unregistration is done
 	 * here; the disconnect callback already did the rest. */
-	if (!ov511->dev) {
-		ov511_dealloc(ov511, 1);
-		video_unregister_device(&ov511->vdev);
-		kfree(ov511);
-		ov511 = NULL;
+	if (!ov->dev) {
+		down(&ov->cbuf_lock);
+		kfree(ov->cbuf);
+		ov->cbuf = NULL;
+		up(&ov->cbuf_lock);
+
+		ov51x_dealloc(ov, 1);
+		video_unregister_device(&ov->vdev);
+		kfree(ov);
+		ov = NULL;
 	}
 }
 
 static int 
-ov511_init_done(struct video_device *vdev)
+ov51x_v4l1_init_done(struct video_device *vdev)
 {
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-	create_proc_ov511_cam((struct usb_ov511 *)vdev);
+	create_proc_ov511_cam(vdev->priv);
 #endif
 
 	return 0;
 }
 
 static long 
-ov511_write(struct video_device *vdev, const char *buf,
-	    unsigned long count, int noblock)
+ov51x_v4l1_write(struct video_device *vdev, const char *buf,
+		 unsigned long count, int noblock)
 {
 	return -EINVAL;
 }
 
 /* Do not call this function directly! */
 static int 
-ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg)
+ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
+			  void *arg)
 {
-	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
+	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
-	if (!ov511->dev)
+	if (!ov->dev)
 		return -EIO;	
 
 	switch (cmd) {
@@ -4839,20 +4771,20 @@
 
 		memset(&b, 0, sizeof(b));
 		sprintf(b.name, "%s USB Camera",
-			ov511->bridge == BRG_OV511 ? "OV511" :
-			ov511->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov511->bridge == BRG_OV518 ? "OV518" :
-			ov511->bridge == BRG_OV518PLUS ? "OV518+" :
+			ov->bridge == BRG_OV511 ? "OV511" :
+			ov->bridge == BRG_OV511PLUS ? "OV511+" :
+			ov->bridge == BRG_OV518 ? "OV518" :
+			ov->bridge == BRG_OV518PLUS ? "OV518+" :
 			"unknown");
 		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-		if (ov511->has_tuner)
+		if (ov->has_tuner)
 			b.type |= VID_TYPE_TUNER;
-		b.channels = ov511->num_inputs;
-		b.audios = ov511->has_audio_proc ? 1:0;
-		b.maxwidth = ov511->maxwidth;
-		b.maxheight = ov511->maxheight;
-		b.minwidth = ov511->minwidth;
-		b.minheight = ov511->minheight;
+		b.channels = ov->num_inputs;
+		b.audios = ov->has_audio_proc ? 1:0;
+		b.maxwidth = ov->maxwidth;
+		b.maxheight = ov->maxheight;
+		b.minwidth = ov->minwidth;
+		b.minheight = ov->minheight;
 
 		if (copy_to_user(arg, &b, sizeof(b)))
 			return -EFAULT;
@@ -4868,18 +4800,18 @@
 		if (copy_from_user(&v, arg, sizeof(v)))
 			return -EFAULT;
 
-		if ((unsigned)(v.channel) >= ov511->num_inputs) {
+		if ((unsigned)(v.channel) >= ov->num_inputs) {
 			err("Invalid channel (%d)", v.channel);
 			return -EINVAL;
 		}
 
-		v.norm = ov511->norm;
-		v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
-		v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0;
-		v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
-//		v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0;
-		v.tuners = (ov511->has_tuner) ? 1:0;
-		decoder_get_input_name(ov511, v.channel, v.name);
+		v.norm = ov->norm;
+		v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
+		v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
+		v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
+//		v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+		v.tuners = (ov->has_tuner) ? 1:0;
+		decoder_get_input_name(ov, v.channel, v.name);
 
 		if (copy_to_user(arg, &v, sizeof(v)))
 			return -EFAULT;
@@ -4897,7 +4829,7 @@
 			return -EFAULT;
 
 		/* Make sure it's not a camera */
-		if (!ov511->has_decoder) {
+		if (!ov->has_decoder) {
 			if (v.channel == 0)
 				return 0;
 			else
@@ -4912,16 +4844,16 @@
 			return -EINVAL;
 		}
 
-		if ((unsigned)(v.channel) >= ov511->num_inputs) {
+		if ((unsigned)(v.channel) >= ov->num_inputs) {
 			err("Invalid channel (%d)", v.channel);
 			return -EINVAL;
 		}
 
-		err = decoder_set_input(ov511, v.channel);
+		err = decoder_set_input(ov, v.channel);
 		if (err)
 			return err;
 
-		err = decoder_set_norm(ov511, v.norm);
+		err = decoder_set_norm(ov, v.norm);
 		if (err)
 			return err;
 
@@ -4935,7 +4867,7 @@
 
 		memset(&p, 0, sizeof(p));
 
-		if (sensor_get_picture(ov511, &p))
+		if (sensor_get_picture(ov, &p))
 			return -EIO;
 
 		if (copy_to_user(arg, &p, sizeof(p)))
@@ -4953,10 +4885,10 @@
 		if (copy_from_user(&p, arg, sizeof(p)))
 			return -EFAULT;
 
-		if (!ov511_get_depth(p.palette))
+		if (!get_depth(p.palette))
 			return -EINVAL;
 
-		if (sensor_set_picture(ov511, &p))
+		if (sensor_set_picture(ov, &p))
 			return -EIO;
 
 		if (force_palette && p.palette != force_palette) {
@@ -4965,23 +4897,22 @@
 		}
 
 		// FIXME: Format should be independent of frames
-		if (p.palette != ov511->frame[0].format) {
+		if (p.palette != ov->frame[0].format) {
 			PDEBUG(4, "Detected format change");
 
 			/* If we're collecting previous frame wait
 			   before changing modes */
-			interruptible_sleep_on(&ov511->wq);
+			interruptible_sleep_on(&ov->wq);
 			if (signal_pending(current)) return -EINTR;
 
-			mode_init_regs(ov511, ov511->frame[0].width,
-				ov511->frame[0].height,	p.palette,
-				ov511->sub_flag);
+			mode_init_regs(ov, ov->frame[0].width,
+				ov->frame[0].height, p.palette, ov->sub_flag);
 		}
 
 		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov511->frame[i].depth = p.depth;
-			ov511->frame[i].format = p.palette;
+			ov->frame[i].depth = p.depth;
+			ov->frame[i].format = p.palette;
 		}
 
 		return 0;
@@ -4994,7 +4925,7 @@
 
 		if (copy_from_user(&vf, arg, sizeof(vf)))
 			return -EFAULT;
-		ov511->sub_flag = vf;
+		ov->sub_flag = vf;
 		return 0;
 	}
 	case VIDIOCSCAPTURE:
@@ -5022,10 +4953,10 @@
 		if (vc.height == 0)
 			vc.height = 16;
 
-		ov511->subx = vc.x;
-		ov511->suby = vc.y;
-		ov511->subw = vc.width;
-		ov511->subh = vc.height;
+		ov->subx = vc.x;
+		ov->suby = vc.y;
+		ov->subw = vc.width;
+		ov->subh = vc.height;
 
 		return 0;
 	}
@@ -5045,25 +4976,25 @@
 			return -EINVAL;
 		if (vw.clipcount)
 			return -EINVAL;
-		if (vw.height != ov511->maxheight)
+		if (vw.height != ov->maxheight)
 			return -EINVAL;
-		if (vw.width != ov511->maxwidth)
+		if (vw.width != ov->maxwidth)
 			return -EINVAL;
 #endif
 
 		/* If we're collecting previous frame wait
 		   before changing modes */
-		interruptible_sleep_on(&ov511->wq);
+		interruptible_sleep_on(&ov->wq);
 		if (signal_pending(current)) return -EINTR;
 
-		result = mode_init_regs(ov511, vw.width, vw.height,
-			ov511->frame[0].format, ov511->sub_flag);
+		result = mode_init_regs(ov, vw.width, vw.height,
+			ov->frame[0].format, ov->sub_flag);
 		if (result < 0)
 			return result;
 
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov511->frame[i].width = vw.width;
-			ov511->frame[i].height = vw.height;
+			ov->frame[i].width = vw.width;
+			ov->frame[i].height = vw.height;
 		}
 
 		return 0;
@@ -5075,8 +5006,8 @@
 		memset(&vw, 0, sizeof(vw));
 		vw.x = 0;		/* FIXME */
 		vw.y = 0;
-		vw.width = ov511->frame[0].width;
-		vw.height = ov511->frame[0].height;
+		vw.width = ov->frame[0].width;
+		vw.height = ov->frame[0].height;
 		vw.flags = 30;
 
 		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
@@ -5095,13 +5026,13 @@
 
 		memset(&vm, 0, sizeof(vm));
 		vm.size = OV511_NUMFRAMES
-			* MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
+			* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
 		vm.frames = OV511_NUMFRAMES;
 
 		vm.offsets[0] = 0;
 		for (i = 1; i < OV511_NUMFRAMES; i++) {
 			vm.offsets[i] = vm.offsets[i-1]
-			   + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
+			   + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
 		}
 
 		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
@@ -5121,7 +5052,7 @@
 		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
 			vm.frame, vm.width, vm.height, vm.format);
 
-		depth = ov511_get_depth(vm.format);
+		depth = get_depth(vm.format);
 		if (!depth) {
 			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
 			return -EINVAL;
@@ -5132,13 +5063,13 @@
 			return -EINVAL;
 		}
 
-		if (vm.width > ov511->maxwidth 
-		    || vm.height > ov511->maxheight) {
+		if (vm.width > ov->maxwidth 
+		    || vm.height > ov->maxheight) {
 			err("VIDIOCMCAPTURE: requested dimensions too big");
 			return -EINVAL;
 		}
 
-		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) {
+		if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) {
 			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
 			return -EBUSY;
 		}
@@ -5148,38 +5079,38 @@
 			return -EINVAL;
 		}
 
-		if ((ov511->frame[vm.frame].width != vm.width) ||
-		    (ov511->frame[vm.frame].height != vm.height) ||
-		    (ov511->frame[vm.frame].format != vm.format) ||
-		    (ov511->frame[vm.frame].sub_flag != ov511->sub_flag) ||
-		    (ov511->frame[vm.frame].depth != depth)) {
+		if ((ov->frame[vm.frame].width != vm.width) ||
+		    (ov->frame[vm.frame].height != vm.height) ||
+		    (ov->frame[vm.frame].format != vm.format) ||
+		    (ov->frame[vm.frame].sub_flag != ov->sub_flag) ||
+		    (ov->frame[vm.frame].depth != depth)) {
 			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
 
 			/* If we're collecting previous frame wait
 			   before changing modes */
-			interruptible_sleep_on(&ov511->wq);
+			interruptible_sleep_on(&ov->wq);
 			if (signal_pending(current)) return -EINTR;
-			ret = mode_init_regs(ov511, vm.width, vm.height,
-				vm.format, ov511->sub_flag);
+			ret = mode_init_regs(ov, vm.width, vm.height,
+				vm.format, ov->sub_flag);
 #if 0
 			if (ret < 0) {
 				PDEBUG(1, "Got error while initializing regs ");
 				return ret;
 			}
 #endif
-			ov511->frame[vm.frame].width = vm.width;
-			ov511->frame[vm.frame].height = vm.height;
-			ov511->frame[vm.frame].format = vm.format;
-			ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
-			ov511->frame[vm.frame].depth = depth;
+			ov->frame[vm.frame].width = vm.width;
+			ov->frame[vm.frame].height = vm.height;
+			ov->frame[vm.frame].format = vm.format;
+			ov->frame[vm.frame].sub_flag = ov->sub_flag;
+			ov->frame[vm.frame].depth = depth;
 		}
 
 		/* Mark it as ready */
-		ov511->frame[vm.frame].grabstate = FRAME_READY;
+		ov->frame[vm.frame].grabstate = FRAME_READY;
 
 		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);
 
-		return ov511_new_frame(ov511, vm.frame);
+		return ov51x_new_frame(ov, vm.frame);
 	}
 	case VIDIOCSYNC:
 	{
@@ -5194,7 +5125,7 @@
 			return -EINVAL;
 		}
 
-		frame = &ov511->frame[fnum];
+		frame = &ov->frame[fnum];
 
 		PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
 		       frame->grabstate);
@@ -5206,7 +5137,7 @@
 		case FRAME_GRABBING:
 		case FRAME_ERROR:
 redo:
-			if (!ov511->dev)
+			if (!ov->dev)
 				return -EIO;
 
 			rc = wait_event_interruptible(frame->wq,
@@ -5219,15 +5150,15 @@
 			if (frame->grabstate == FRAME_ERROR) {
 				int ret;
 
-				if ((ret = ov511_new_frame(ov511, fnum)) < 0)
+				if ((ret = ov51x_new_frame(ov, fnum)) < 0)
 					return ret;
 				goto redo;
 			}
 			/* Fall through */			
 		case FRAME_DONE:
-			if (ov511->snap_enabled && !frame->snapshot) {
+			if (ov->snap_enabled && !frame->snapshot) {
 				int ret;
-				if ((ret = ov511_new_frame(ov511, fnum)) < 0)
+				if ((ret = ov51x_new_frame(ov, fnum)) < 0)
 					return ret;
 				goto redo;
 			}
@@ -5236,13 +5167,13 @@
 
 			/* Reset the hardware snapshot button */
 			/* FIXME - Is this the best place for this? */
-			if ((ov511->snap_enabled) && (frame->snapshot)) {
+			if ((ov->snap_enabled) && (frame->snapshot)) {
 				frame->snapshot = 0;
-				ov51x_clear_snapshot(ov511);
+				ov51x_clear_snapshot(ov);
 			}
 
 			/* Decompression, format conversion, etc... */
-			ov511_postprocess(ov511, frame);
+			ov51x_postprocess(ov, frame);
 
 			break;
 		} /* end switch */
@@ -5271,7 +5202,7 @@
 
 		memset(&vu, 0, sizeof(vu));
 
-		vu.video = ov511->vdev.minor;	/* Video minor */
+		vu.video = ov->vdev.minor;	/* Video minor */
 		vu.vbi = VIDEO_NO_UNIT;		/* VBI minor */
 		vu.radio = VIDEO_NO_UNIT;	/* Radio minor */
 		vu.audio = VIDEO_NO_UNIT;	/* Audio minor */
@@ -5291,7 +5222,7 @@
 		if (copy_from_user(&v, arg, sizeof(v)))
 			return -EFAULT;
 
-		if (!ov511->has_tuner || v.tuner)	// Only tuner 0
+		if (!ov->has_tuner || v.tuner)	// Only tuner 0
 			return -EINVAL;
 
 		strcpy(v.name, "Television");
@@ -5305,7 +5236,7 @@
 		v.mode = 0; 		/* FIXME:  Not sure what this is yet */
 		v.signal = 0xFFFF;	/* unknown */
 
-		call_i2c_clients(ov511, cmd, &v);
+		call_i2c_clients(ov, cmd, &v);
 
 		if (copy_to_user(arg, &v, sizeof(v)))
 			return -EFAULT;
@@ -5323,7 +5254,7 @@
 			return -EFAULT;
 
 		/* Only no or one tuner for now */
-		if (!ov511->has_tuner || v.tuner)
+		if (!ov->has_tuner || v.tuner)
 			return -EINVAL;
 
 		/* and it only has certain valid modes */
@@ -5332,21 +5263,21 @@
 		    v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;
 
 		/* Is this right/necessary? */
-		err = decoder_set_norm(ov511, v.mode);
+		err = decoder_set_norm(ov, v.mode);
 		if (err)
 			return err;
 
-		call_i2c_clients(ov511, cmd, &v);
+		call_i2c_clients(ov, cmd, &v);
 
 		return 0;
 	}
 	case VIDIOCGFREQ:
 	{
-		unsigned long v = ov511->freq;
+		unsigned long v = ov->freq;
 
 		PDEBUG(4, "VIDIOCGFREQ");
 
-		if (!ov511->has_tuner)
+		if (!ov->has_tuner)
 			return -EINVAL;
 #if 0
 		/* FIXME: this is necessary for testing */
@@ -5361,7 +5292,7 @@
 	{
 		unsigned long v;
 
-		if (!ov511->has_tuner)
+		if (!ov->has_tuner)
 			return -EINVAL;
 
 		if (copy_from_user(&v, arg, sizeof(v)))
@@ -5369,8 +5300,8 @@
 
 		PDEBUG(4, "VIDIOCSFREQ: %lx", v);
 
-		ov511->freq = v;
-		call_i2c_clients(ov511, cmd, &v);
+		ov->freq = v;
+		call_i2c_clients(ov, cmd, &v);
 
 		return 0;
 	}
@@ -5389,29 +5320,29 @@
 }
 
 static int 
-ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	int rc;
-	struct usb_ov511 *ov511 = vdev->priv;
+	struct usb_ov511 *ov = vdev->priv;
 
-	if (down_interruptible(&ov511->lock))
+	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov511_ioctl_internal(vdev, cmd, arg);
+	rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg);
 
-	up(&ov511->lock);
+	up(&ov->lock);
 	return rc;
 }
 
 static inline long 
-ov511_read(struct video_device *vdev, char *buf, unsigned long count,
-	   int noblock)
+ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
+		int noblock)
 {
-	struct usb_ov511 *ov511 = vdev->priv;
+	struct usb_ov511 *ov = vdev->priv;
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
 
-	if (down_interruptible(&ov511->lock))
+	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
 	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
@@ -5421,16 +5352,16 @@
 		goto error;
 	}
 
-	if (!ov511->dev) {
+	if (!ov->dev) {
 		rc = -EIO;
 		goto error;
 	}
 
 // FIXME: Only supports two frames
 	/* See if a frame is completed, then use it. */
-	if (ov511->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
+	if (ov->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
 		frmx = 0;
-	else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+	else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
 		frmx = 1;
 
 	/* If nonblocking we return immediately */
@@ -5442,24 +5373,24 @@
 	/* If no FRAME_DONE, look for a FRAME_GRABBING state. */
 	/* See if a frame is in process (grabbing), then use it. */
 	if (frmx == -1) {
-		if (ov511->frame[0].grabstate == FRAME_GRABBING)
+		if (ov->frame[0].grabstate == FRAME_GRABBING)
 			frmx = 0;
-		else if (ov511->frame[1].grabstate == FRAME_GRABBING)
+		else if (ov->frame[1].grabstate == FRAME_GRABBING)
 			frmx = 1;
 	}
 
 	/* If no frame is active, start one. */
 	if (frmx == -1) {
-		if ((rc = ov511_new_frame(ov511, frmx = 0))) {
-			err("read: ov511_new_frame error");
+		if ((rc = ov51x_new_frame(ov, frmx = 0))) {
+			err("read: ov51x_new_frame error");
 			goto error;
 		}
 	}
 
-	frame = &ov511->frame[frmx];
+	frame = &ov->frame[frmx];
 
 restart:
-	if (!ov511->dev) {
+	if (!ov->dev) {
 		rc = -EIO;
 		goto error;
 	}
@@ -5478,9 +5409,9 @@
 
 	if (frame->grabstate == FRAME_ERROR) {
 		frame->bytes_read = 0;
-		err("** ick! ** Errored frame %d", ov511->curframe);
-		if (ov511_new_frame(ov511, frmx)) {
-			err("read: ov511_new_frame error");
+		err("** ick! ** Errored frame %d", ov->curframe);
+		if (ov51x_new_frame(ov, frmx)) {
+			err("read: ov51x_new_frame error");
 			goto error;
 		}
 		goto restart;
@@ -5488,25 +5419,25 @@
 
 
 	/* Repeat until we get a snapshot frame */
-	if (ov511->snap_enabled)
+	if (ov->snap_enabled)
 		PDEBUG(4, "Waiting snapshot frame");
-	if (ov511->snap_enabled && !frame->snapshot) {
+	if (ov->snap_enabled && !frame->snapshot) {
 		frame->bytes_read = 0;
-		if ((rc = ov511_new_frame(ov511, frmx))) {
-			err("read: ov511_new_frame error");
+		if ((rc = ov51x_new_frame(ov, frmx))) {
+			err("read: ov51x_new_frame error");
 			goto error;
 		}
 		goto restart;
 	}
 
 	/* Clear the snapshot */
-	if (ov511->snap_enabled && frame->snapshot) {
+	if (ov->snap_enabled && frame->snapshot) {
 		frame->snapshot = 0;
-		ov51x_clear_snapshot(ov511);
+		ov51x_clear_snapshot(ov);
 	}
 
 	/* Decompression, format conversion, etc... */
-	ov511_postprocess(ov511, frame);
+	ov51x_postprocess(ov, frame);
 
 	PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
 		frame->bytes_read,
@@ -5538,48 +5469,48 @@
 
 // FIXME: Only supports two frames
 		/* Mark it as available to be used again. */
-		ov511->frame[frmx].grabstate = FRAME_UNUSED;
-		if ((rc = ov511_new_frame(ov511, !frmx))) {
-			err("ov511_new_frame returned error");
+		ov->frame[frmx].grabstate = FRAME_UNUSED;
+		if ((rc = ov51x_new_frame(ov, !frmx))) {
+			err("ov51x_new_frame returned error");
 			goto error;
 		}
 	}
 
 	PDEBUG(4, "read finished, returning %ld (sweet)", count);
 
-	up(&ov511->lock);
+	up(&ov->lock);
 	return count;
 
 error:
-	up(&ov511->lock);
+	up(&ov->lock);
 	return rc;
 }
 
 static int 
-ov511_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size)
 {
-	struct usb_ov511 *ov511 = vdev->priv;
+	struct usb_ov511 *ov = vdev->priv;
 	unsigned long start = (unsigned long)adr;
 	unsigned long page, pos;
 
-	if (ov511->dev == NULL)
+	if (ov->dev == NULL)
 		return -EIO;
 
 	PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
 
 	if (size > (((OV511_NUMFRAMES
-	              * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)
+	              * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
 	              + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
 		return -EINVAL;
 
-	if (down_interruptible(&ov511->lock))
+	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	pos = (unsigned long)ov511->fbuf;
+	pos = (unsigned long)ov->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&ov511->lock);
+			up(&ov->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -5590,43 +5521,42 @@
 			size = 0;
 	}
 
-	up(&ov511->lock);
+	up(&ov->lock);
 	return 0;
 }
 
-static struct video_device ov511_template = {
+static struct video_device vdev_template = {
 	owner:		THIS_MODULE,
 	name:		"OV511 USB Camera",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_OV511,
-	open:		ov511_open,
-	close:		ov511_close,
-	read:		ov511_read,
-	write:		ov511_write,
-	ioctl:		ov511_ioctl,
-	mmap:		ov511_mmap,
-	initialize:	ov511_init_done,
+	open:		ov51x_v4l1_open,
+	close:		ov51x_v4l1_close,
+	read:		ov51x_v4l1_read,
+	write:		ov51x_v4l1_write,
+	ioctl:		ov51x_v4l1_ioctl,
+	mmap:		ov51x_v4l1_mmap,
+	initialize:	ov51x_v4l1_init_done,
 };
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 static int 
-ov511_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 		    unsigned long ularg)
 {
-	struct proc_dir_entry *pde;
-	struct usb_ov511 *ov511;
+	struct proc_dir_entry *pde = inode->u.generic_ip;
+	struct usb_ov511 *ov;
 	void *arg = (void *) ularg;
 	int rc;
 
-	pde = (struct proc_dir_entry *) inode->u.generic_ip;
 	if (!pde)
 		return -ENOENT;
 
-	ov511 = (struct usb_ov511 *) pde->data;
-	if (!ov511)
+	ov = pde->data;
+	if (!ov)
 		return -ENODEV;
 
-	if (!ov511->dev)
+	if (!ov->dev)
 		return -EIO;
 
 	/* Should we pass through standard V4L IOCTLs? */
@@ -5651,19 +5581,19 @@
 
 		switch (opt.optnum) {
 		case OV511_USOPT_BRIGHT:
-			rc = sensor_get_brightness(ov511, &(opt.val));
+			rc = sensor_get_brightness(ov, &(opt.val));
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_SAT:
-			rc = sensor_get_saturation(ov511, &(opt.val));
+			rc = sensor_get_saturation(ov, &(opt.val));
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_HUE:
-			rc = sensor_get_hue(ov511, &(opt.val));
+			rc = sensor_get_hue(ov, &(opt.val));
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_CONTRAST:
-			rc = sensor_get_contrast(ov511, &(opt.val));
+			rc = sensor_get_contrast(ov, &(opt.val));
 			if (rc)	return rc;
 			break;
 		default:
@@ -5685,19 +5615,19 @@
 
 		switch (opt.optnum) {
 		case OV511_USOPT_BRIGHT:
-			rc = sensor_set_brightness(ov511, opt.val);
+			rc = sensor_set_brightness(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_SAT:
-			rc = sensor_set_saturation(ov511, opt.val);
+			rc = sensor_set_saturation(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_HUE:
-			rc = sensor_set_hue(ov511, opt.val);
+			rc = sensor_set_hue(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		case OV511_USOPT_CONTRAST:
-			rc = sensor_set_contrast(ov511, opt.val);
+			rc = sensor_set_contrast(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		default:
@@ -5716,19 +5646,19 @@
 
 		switch (opt.optnum) {
 		case OV511_UIOPT_POWER_FREQ:
-			opt.val = ov511->lightfreq;
+			opt.val = ov->lightfreq;
 			break;
 		case OV511_UIOPT_BFILTER:
-			opt.val = ov511->bandfilt;
+			opt.val = ov->bandfilt;
 			break;
 		case OV511_UIOPT_LED:
-			opt.val = ov511->led_policy;
+			opt.val = ov->led_policy;
 			break;
 		case OV511_UIOPT_DEBUG:
 			opt.val = debug;
 			break;
 		case OV511_UIOPT_COMPRESS:
-			opt.val = ov511->compress;
+			opt.val = ov->compress;
 			break;
 		default:
 			err("Invalid get int option number");
@@ -5749,20 +5679,20 @@
 
 		switch (opt.optnum) {
 		case OV511_UIOPT_POWER_FREQ:
-			rc = sensor_set_light_freq(ov511, opt.val);
+			rc = sensor_set_light_freq(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		case OV511_UIOPT_BFILTER:
-			rc = sensor_set_banding_filter(ov511, opt.val);
+			rc = sensor_set_banding_filter(ov, opt.val);
 			if (rc)	return rc;
 			break;
 		case OV511_UIOPT_LED:
 			if (opt.val <= 2) {
-				ov511->led_policy = opt.val;
-				if (ov511->led_policy == LED_OFF)
-					ov51x_led_control(ov511, 0);
-				else if (ov511->led_policy == LED_ON)
-					ov51x_led_control(ov511, 1);
+				ov->led_policy = opt.val;
+				if (ov->led_policy == LED_OFF)
+					ov51x_led_control(ov, 0);
+				else if (ov->led_policy == LED_ON)
+					ov51x_led_control(ov, 1);
 			} else {
 				return -EINVAL;
 			}
@@ -5774,14 +5704,12 @@
 				return -EINVAL;
 			break;
 		case OV511_UIOPT_COMPRESS:
-			ov511->compress = opt.val;
-			if (ov511->compress) {
-				if (ov511->bridge == BRG_OV511 ||
-				    ov511->bridge == BRG_OV511PLUS)
-					ov511_init_compression(ov511);
-				else if (ov511->bridge == BRG_OV518 ||
-					 ov511->bridge == BRG_OV518PLUS)
-					ov518_init_compression(ov511);
+			ov->compress = opt.val;
+			if (ov->compress) {
+				if (ov->bclass == BCL_OV511)
+					ov511_init_compression(ov);
+				else if (ov->bclass == BCL_OV518)
+					ov518_init_compression(ov);
 			}
 			break;
 		default:
@@ -5798,7 +5726,7 @@
 		if (copy_from_user(&w, arg, sizeof(w)))
 			return -EFAULT;
 
-		return ov51x_i2c_write_slave(ov511, w.slave, w.reg, w.value,
+		return i2c_w_slave(ov, w.slave, w.reg, w.value,
 			w.mask);
 	}
 	case OV511IOC_RI2C:
@@ -5808,7 +5736,7 @@
 		if (copy_from_user(&r, arg, sizeof(r)))
 			return -EFAULT;
 
-		rc = ov51x_i2c_read_slave(ov511, r.slave, r.reg);
+		rc = i2c_r_slave(ov, r.slave, r.reg);
 		if (rc < 0)
 			return rc;
 
@@ -5837,7 +5765,7 @@
  * the same register settings as the OV7610, since they are very similar.
  */
 static int 
-ov7xx0_configure(struct usb_ov511 *ov511)
+ov7xx0_configure(struct usb_ov511 *ov)
 {
 	int i, success;
 	int rc;
@@ -5954,16 +5882,15 @@
 	PDEBUG(4, "starting configuration");
 
 	/* This looks redundant, but is necessary for WebCam 3 */
-	ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID;
-	if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID,
-				OV7xx0_I2C_READ_ID) < 0)
+	ov->primary_i2c_slave = OV7xx0_SID;
+	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
 		return -1;
 
-	if (ov51x_init_ov_sensor(ov511) >= 0) {
+	if (init_ov_sensor(ov) >= 0) {
 		PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
 	} else {
 		/* Reset the 76xx */
-		if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -1;
+		if (i2c_w(ov, 0x12, 0x80) < 0) return -1;
 
 		/* Wait for it to initialize */
 		schedule_timeout(1 + 150 * HZ / 1000);
@@ -5971,10 +5898,8 @@
 		i = 0;
 		success = 0;
 		while (i <= i2c_detect_tries) {
-			if ((ov51x_i2c_read(ov511,
-					    OV7610_REG_ID_HIGH) == 0x7F) &&
-			    (ov51x_i2c_read(ov511,
-					    OV7610_REG_ID_LOW) == 0xA2)) {
+			if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+			    (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
 				success = 1;
 				break;
 			} else {
@@ -5998,17 +5923,17 @@
 	}
 
 	/* Detect sensor (sub)type */
-	rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I);
+	rc = i2c_r(ov, OV7610_REG_COM_I);
 
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
 	} else if ((rc & 3) == 3) {
 		info("Sensor is an OV7610");
-		ov511->sensor = SEN_OV7610;
+		ov->sensor = SEN_OV7610;
 	} else if ((rc & 3) == 1) {
 		/* I don't know what's different about the 76BE yet */
-		if (ov51x_i2c_read(ov511, 0x15) & 1)
+		if (i2c_r(ov, 0x15) & 1)
 			info("Sensor is an OV7620AE");
 		else
 			info("Sensor is an OV76BE");
@@ -6016,48 +5941,48 @@
 		/* OV511+ will return all zero isoc data unless we
 		 * configure the sensor as a 7620. Someone needs to
 		 * find the exact reg. setting that causes this. */
-		if (ov511->bridge == BRG_OV511PLUS) {
+		if (ov->bridge == BRG_OV511PLUS) {
 			info("Enabling 511+/7620AE workaround");
-			ov511->sensor = SEN_OV7620;
+			ov->sensor = SEN_OV7620;
 		} else {
-			ov511->sensor = SEN_OV7620AE;
+			ov->sensor = SEN_OV7620AE;
 		}
 	} else if ((rc & 3) == 0) {
 		info("Sensor is an OV7620");
-		ov511->sensor = SEN_OV7620;
+		ov->sensor = SEN_OV7620;
 	} else {
 		err("Unknown image sensor version: %d", rc & 3);
 		return -1;
 	}
 
-	if (ov511->sensor == SEN_OV7620) {
+	if (ov->sensor == SEN_OV7620) {
 		PDEBUG(4, "Writing 7620 registers");
-		if (ov511_write_regvals(ov511, aRegvalsNorm7620))
+		if (write_regvals(ov, aRegvalsNorm7620))
 			return -1;
 	} else {
 		PDEBUG(4, "Writing 7610 registers");
-		if (ov511_write_regvals(ov511, aRegvalsNorm7610))
+		if (write_regvals(ov, aRegvalsNorm7610))
 			return -1;
 	}
 
 	/* Set sensor-specific vars */
-	ov511->maxwidth = 640;
-	ov511->maxheight = 480;
-	ov511->minwidth = 64;
-	ov511->minheight = 48;
+	ov->maxwidth = 640;
+	ov->maxheight = 480;
+	ov->minwidth = 64;
+	ov->minheight = 48;
 
 	// FIXME: These do not match the actual settings yet
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x80 << 8;
-	ov511->colour = 0x80 << 8;
-	ov511->hue = 0x80 << 8;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x80 << 8;
+	ov->colour = 0x80 << 8;
+	ov->hue = 0x80 << 8;
 
 	return 0;
 }
 
 /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
 static int 
-ov6xx0_configure(struct usb_ov511 *ov511)
+ov6xx0_configure(struct usb_ov511 *ov)
 {
 	int rc;
 
@@ -6183,7 +6108,7 @@
 
 	PDEBUG(4, "starting sensor configuration");
 	
-	if (ov51x_init_ov_sensor(ov511) < 0) {
+	if (init_ov_sensor(ov) < 0) {
 		err("Failed to read sensor ID. You might not have an OV6xx0,");
 		err("or it may be not responding. Report this to " EMAIL);
 		return -1;
@@ -6192,50 +6117,44 @@
 	}
 
 	/* Detect sensor (sub)type */
-	rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I);
+	rc = i2c_r(ov, OV7610_REG_COM_I);
 
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
 	} else if ((rc & 3) == 0) {
 		info("Sensor is an OV6630");
-		ov511->sensor = SEN_OV6630;
+		ov->sensor = SEN_OV6630;
 	} else if ((rc & 3) == 1) {
 		info("Sensor is an OV6620");
-		ov511->sensor = SEN_OV6620;
+		ov->sensor = SEN_OV6620;
 	} else if ((rc & 3) == 2) {
 		info("Sensor is an OV6630AE");
-		ov511->sensor = SEN_OV6630;
+		ov->sensor = SEN_OV6630;
 	} else if ((rc & 3) == 3) {
 		info("Sensor is an OV6630AF");
-		ov511->sensor = SEN_OV6630;
+		ov->sensor = SEN_OV6630;
 	} 
 
 	/* Set sensor-specific vars */
-	if (ov511->sensor == SEN_OV6620) {
-		ov511->maxwidth = 352;
-		ov511->maxheight = 288;
-	} else {
-		/* 352x288 not working with OV518 yet */
-		ov511->maxwidth = 320;
-		ov511->maxheight = 240;
-	}
-	ov511->minwidth = 64;
-	ov511->minheight = 48;
+	ov->maxwidth = 352;
+	ov->maxheight = 288;
+	ov->minwidth = 64;
+	ov->minheight = 48;
 
 	// FIXME: These do not match the actual settings yet
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x80 << 8;
-	ov511->colour = 0x80 << 8;
-	ov511->hue = 0x80 << 8;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x80 << 8;
+	ov->colour = 0x80 << 8;
+	ov->hue = 0x80 << 8;
 
-	if (ov511->sensor == SEN_OV6620) {
+	if (ov->sensor == SEN_OV6620) {
 		PDEBUG(4, "Writing 6x20 registers");
-		if (ov511_write_regvals(ov511, aRegvalsNorm6x20))
+		if (write_regvals(ov, aRegvalsNorm6x20))
 			return -1;
 	} else {
 		PDEBUG(4, "Writing 6x30 registers");
-		if (ov511_write_regvals(ov511, aRegvalsNorm6x30))
+		if (write_regvals(ov, aRegvalsNorm6x30))
 			return -1;
 	}
 	
@@ -6244,13 +6163,13 @@
 
 /* This initializes the KS0127 and KS0127B video decoders. */
 static int 
-ks0127_configure(struct usb_ov511 *ov511)
+ks0127_configure(struct usb_ov511 *ov)
 {
 	int rc;
 
 // FIXME: I don't know how to sync or reset it yet
 #if 0
-	if (ov51x_init_ks_sensor(ov511) < 0) {
+	if (ov51x_init_ks_sensor(ov) < 0) {
 		err("Failed to initialize the KS0127");
 		return -1;
 	} else {
@@ -6259,21 +6178,21 @@
 #endif
 
 	/* Detect decoder subtype */
-	rc = ov51x_i2c_read(ov511, 0x00);
+	rc = i2c_r(ov, 0x00);
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
 	} else if (rc & 0x08) {
-		rc = ov51x_i2c_read(ov511, 0x3d);
+		rc = i2c_r(ov, 0x3d);
 		if (rc < 0) {
 			err("Error detecting sensor type");
 			return -1;
 		} else if ((rc & 0x0f) == 0) {
 			info("Sensor is a KS0127");
-			ov511->sensor = SEN_KS0127;
+			ov->sensor = SEN_KS0127;
 		} else if ((rc & 0x0f) == 9) {
 			info("Sensor is a KS0127B Rev. A");
-			ov511->sensor = SEN_KS0127B;
+			ov->sensor = SEN_KS0127B;
 		}
 	} else {
 		err("Error: Sensor is an unsupported KS0122");
@@ -6281,16 +6200,16 @@
 	}
 
 	/* Set sensor-specific vars */
-	ov511->maxwidth = 640;
-	ov511->maxheight = 480;
-	ov511->minwidth = 64;
-	ov511->minheight = 48;
+	ov->maxwidth = 640;
+	ov->maxheight = 480;
+	ov->minwidth = 64;
+	ov->minheight = 48;
 
 	// FIXME: These do not match the actual settings yet
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x80 << 8;
-	ov511->colour = 0x80 << 8;
-	ov511->hue = 0x80 << 8;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x80 << 8;
+	ov->colour = 0x80 << 8;
+	ov->hue = 0x80 << 8;
 
 	/* This device is not supported yet. Bail out now... */
 	err("This sensor is not supported yet.");
@@ -6303,7 +6222,6 @@
 static int 
 saa7111a_configure(struct usb_ov511 *ov511)
 {
-	struct usb_device *dev = ov511->dev;
 	int rc;
 
 	/* Since there is no register reset command, all registers must be
@@ -6338,7 +6256,7 @@
 
 // FIXME: I don't know how to sync or reset it yet
 #if 0
-	if (ov51x_init_saa_sensor(ov511) < 0) {
+	if (ov51x_init_saa_sensor(ov) < 0) {
 		err("Failed to initialize the SAA7111A");
 		return -1;
 	} else {
@@ -6365,12 +6283,12 @@
 	ov511->hue = 32768;
 
 	PDEBUG(4, "Writing SAA7111A registers");
-	if (ov511_write_regvals(ov511, aRegvalsNormSAA7111A))
+	if (write_regvals(ov511, aRegvalsNormSAA7111A))
 		return -1;
 
 	/* Detect version of decoder. This must be done after writing the
          * initial regs or the decoder will lock up. */
-	rc = ov51x_i2c_read(ov511, 0x00);
+	rc = i2c_r(ov511, 0x00);
 
 	if (rc < 0) {
 		err("Error detecting sensor version");
@@ -6383,8 +6301,8 @@
 	// FIXME: Fix this for OV518(+)
 	/* Latch to negative edge of clock. Otherwise, we get incorrect
 	 * colors and jitter in the digital signal. */
-	if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS)
-		ov511_reg_write(dev, 0x11, 0x00);
+	if (ov511->bclass == BCL_OV511)
+		reg_w(ov511, 0x11, 0x00);
 	else
 		warn("SAA7111A not yet supported with OV518/OV518+");
 
@@ -6393,144 +6311,138 @@
 
 /* This initializes the OV511/OV511+ and the sensor */
 static int 
-ov511_configure(struct usb_ov511 *ov511)
+ov511_configure(struct usb_ov511 *ov)
 {
-	struct usb_device *dev = ov511->dev;
 	int i;
 
 	static struct ov511_regvals aRegvalsInit511[] = {
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
-	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
-	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d },
+		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
+	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
+	 	{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
+		{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_RESET,	0x3f },
+		{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_RESET,	0x3d },
 		{ OV511_DONE_BUS, 0x0, 0x00},
 	};
 
 	static struct ov511_regvals aRegvalsNorm511[] = {
-		{ OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f },
-		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 },
-		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 },
+		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x03 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R511_FIFO_OPTS,	0x1f },
+		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
+		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
 	static struct ov511_regvals aRegvalsNorm511Plus[] = {
-		{ OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0xff },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 },
-		{ OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0xff },
-		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 },
-		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 },
+		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0xff },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x03 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R511_FIFO_OPTS,	0xff },
+		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
+		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
 	PDEBUG(4, "");
 
-	ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
-	if (ov511->customid < 0) {
+	ov->customid = reg_r(ov, R511_SYS_CUST_ID);
+	if (ov->customid < 0) {
 		err("Unable to read camera bridge registers");
 		goto error;
 	}
 
-	ov511->desc = -1;
-	PDEBUG (1, "CustomID = %d", ov511->customid);
+	ov->desc = -1;
+	PDEBUG (1, "CustomID = %d", ov->customid);
 	for (i = 0; clist[i].id >= 0; i++) {
-		if (ov511->customid == clist[i].id) {
+		if (ov->customid == clist[i].id) {
 			info("model: %s", clist[i].description);
-			ov511->desc = i;
+			ov->desc = i;
 			break;
 		}
 	}
 
 	if (clist[i].id == -1) {
-		err("Camera type (%d) not recognized", ov511->customid);
+		err("Camera type (%d) not recognized", ov->customid);
 		err("Please notify " EMAIL " of the name,");
 		err("manufacturer, model, and this number of your camera.");
 		err("Also include the output of the detection process.");
 	} 
 
 	if (clist[i].id == 6) {	/* USB Life TV (NTSC) */
-		ov511->tuner_type = 8;		/* Temic 4036FY5 3X 1981 */
+		ov->tuner_type = 8;		/* Temic 4036FY5 3X 1981 */
 	}
 
-	if (ov511_write_regvals(ov511, aRegvalsInit511)) goto error;
+	if (write_regvals(ov, aRegvalsInit511)) goto error;
 
-	if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO)
-		ov51x_led_control(ov511, 0);
+	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+		ov51x_led_control(ov, 0);
 
 	/* The OV511+ has undocumented bits in the flow control register.
 	 * Setting it to 0xff fixes the corruption with moving objects. */
-	if (ov511->bridge == BRG_OV511) {
-		if (ov511_write_regvals(ov511, aRegvalsNorm511)) goto error;
-	} else if (ov511->bridge == BRG_OV511PLUS) {
-		if (ov511_write_regvals(ov511, aRegvalsNorm511Plus)) goto error;
+	if (ov->bridge == BRG_OV511) {
+		if (write_regvals(ov, aRegvalsNorm511)) goto error;
+	} else if (ov->bridge == BRG_OV511PLUS) {
+		if (write_regvals(ov, aRegvalsNorm511Plus)) goto error;
 	} else {
 		err("Invalid bridge");
 	}
 
-	if (ov511_init_compression(ov511)) goto error;
+	if (ov511_init_compression(ov)) goto error;
 
-	ov511_set_packet_size(ov511, 0);
+	ov51x_set_packet_size(ov, 0);
 
-	ov511->snap_enabled = snapshot;	
+	ov->snap_enabled = snapshot;	
 
 	/* Test for 7xx0 */
 	PDEBUG(3, "Testing for 0V7xx0");
-	ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID;
-	if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID,
-				OV7xx0_I2C_READ_ID) < 0)
+	ov->primary_i2c_slave = OV7xx0_SID;
+	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
 		goto error;
 
-	if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) {
+	if (i2c_w(ov, 0x12, 0x80) < 0) {
 		/* Test for 6xx0 */
 		PDEBUG(3, "Testing for 0V6xx0");
-		ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID;
-		if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID,
-					OV6xx0_I2C_READ_ID) < 0)
+		ov->primary_i2c_slave = OV6xx0_SID;
+		if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
 			goto error;
 
-		if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) {
+		if (i2c_w(ov, 0x12, 0x80) < 0) {
 			/* Test for 8xx0 */
 			PDEBUG(3, "Testing for 0V8xx0");
-			ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID;
-			if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID,
-						OV8xx0_I2C_READ_ID))
+			ov->primary_i2c_slave = OV8xx0_SID;
+			if (ov51x_set_slave_ids(ov, OV8xx0_SID))
 				goto error;
 
-			if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) {
+			if (i2c_w(ov, 0x12, 0x80) < 0) {
 				/* Test for SAA7111A */
 				PDEBUG(3, "Testing for SAA7111A");
-				ov511->primary_i2c_slave = SAA7111A_I2C_WRITE_ID;
-				if (ov51x_set_slave_ids(ov511, SAA7111A_I2C_WRITE_ID,
-							SAA7111A_I2C_READ_ID))
+				ov->primary_i2c_slave = SAA7111A_SID;
+				if (ov51x_set_slave_ids(ov, SAA7111A_SID))
 					goto error;
 
-				if (ov51x_i2c_write(ov511, 0x0d, 0x00) < 0) {
+				if (i2c_w(ov, 0x0d, 0x00) < 0) {
 					/* Test for KS0127 */
 					PDEBUG(3, "Testing for KS0127");
-					ov511->primary_i2c_slave = KS0127_I2C_WRITE_ID;
-					if (ov51x_set_slave_ids(ov511, KS0127_I2C_WRITE_ID,
-								KS0127_I2C_READ_ID))
+					ov->primary_i2c_slave = KS0127_SID;
+					if (ov51x_set_slave_ids(ov, KS0127_SID))
 						goto error;
 
-					if (ov51x_i2c_write(ov511, 0x10, 0x00) < 0) {
+					if (i2c_w(ov, 0x10, 0x00) < 0) {
 						err("Can't determine sensor slave IDs");
 		 				goto error;
 					} else {
-						if(ks0127_configure(ov511) < 0) {
+						if (ks0127_configure(ov) < 0) {
 							err("Failed to configure KS0127");
 	 						goto error;
 						}
 					}
 				} else {
-					if(saa7111a_configure(ov511) < 0) {
+					if (saa7111a_configure(ov) < 0) {
 						err("Failed to configure SAA7111A");
 	 					goto error;
 					}
@@ -6540,13 +6452,13 @@
 				goto error;
 			}
 		} else {
-			if(ov6xx0_configure(ov511) < 0) {
+			if (ov6xx0_configure(ov) < 0) {
 				err("Failed to configure OV6xx0");
  				goto error;
 			}
 		}
 	} else {
-		if(ov7xx0_configure(ov511) < 0) {
+		if (ov7xx0_configure(ov) < 0) {
 			err("Failed to configure OV7xx0");
 	 		goto error;
 		}
@@ -6562,96 +6474,90 @@
 
 /* This initializes the OV518/OV518+ and the sensor */
 static int 
-ov518_configure(struct usb_ov511 *ov511)
+ov518_configure(struct usb_ov511 *ov)
 {
-	struct usb_device *dev = ov511->dev;
-
 	static struct ov511_regvals aRegvalsInit518[] = {
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x40 },
-	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 },
-	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3e },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x00 },
-		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 },
-		{ OV511_REG_BUS, 0x46, 0x00 }, 
-		{ OV511_REG_BUS, 0x5d, 0x03 },
+		{ OV511_REG_BUS, R51x_SYS_RESET,	0x40 },
+	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
+	 	{ OV511_REG_BUS, R51x_SYS_RESET,	0x3e },
+		{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
+		{ OV511_REG_BUS, R51x_SYS_RESET,	0x00 },
+		{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
+		{ OV511_REG_BUS, 0x46,			0x00 }, 
+		{ OV511_REG_BUS, 0x5d,			0x03 },
 		{ OV511_DONE_BUS, 0x0, 0x00},
 	};
 
 	/* New values, based on Windows driver. Since what they do is not
 	 * known yet, this may be incorrect. */
 	static struct ov511_regvals aRegvalsNorm518[] = {
-		{ OV511_REG_BUS, 0x52, 0x02 }, /* Reset snapshot */
-		{ OV511_REG_BUS, 0x52, 0x01 }, /* Enable snapshot */
-		{ OV511_REG_BUS, 0x31, 0x0f },
-		{ OV511_REG_BUS, 0x5d, 0x03 },
-		{ OV511_REG_BUS, 0x24, 0x9f },
-		{ OV511_REG_BUS, 0x25, 0x90 },
-		{ OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */
-		{ OV511_REG_BUS, 0x51, 0x04 },
-		{ OV511_REG_BUS, 0x71, 0x19 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
+		{ OV511_REG_BUS, 0x31, 			0x0f },
+		{ OV511_REG_BUS, 0x5d,			0x03 },
+		{ OV511_REG_BUS, 0x24,			0x9f },
+		{ OV511_REG_BUS, 0x25,			0x90 },
+		{ OV511_REG_BUS, 0x20,			0x00 }, /* Was 0x08 */
+		{ OV511_REG_BUS, 0x51,			0x04 },
+		{ OV511_REG_BUS, 0x71,			0x19 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
 	};
 
 	PDEBUG(4, "");
 
 	/* First 5 bits of custom ID reg are a revision ID on OV518 */
-	info("Device revision %d",
-	     0x1F & ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID));
+	info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
 
-	if (ov511_write_regvals(ov511, aRegvalsInit518)) goto error;
+	if (write_regvals(ov, aRegvalsInit518)) goto error;
 
 	/* Set LED GPIO pin to output mode */
-	if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error;
+	if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error;
 
 	/* LED is off by default with OV518; have to explicitly turn it on */
-	if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO)
-		ov51x_led_control(ov511, 0);
+	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+		ov51x_led_control(ov, 0);
 	else
-		ov51x_led_control(ov511, 1);
+		ov51x_led_control(ov, 1);
 
 	/* Don't require compression if dumppix is enabled; otherwise it's
 	 * required. OV518 has no uncompressed mode, to save RAM. */
-	if (!dumppix && !ov511->compress) {
-		ov511->compress = 1;
+	if (!dumppix && !ov->compress) {
+		ov->compress = 1;
 		warn("Compression required with OV518...enabling");
 	}
 
-	if (ov511_write_regvals(ov511, aRegvalsNorm518)) goto error;
+	if (write_regvals(ov, aRegvalsNorm518)) goto error;
 
-	if (ov511_reg_write(dev, 0x2f,0x80) < 0) goto error;
+	if (reg_w(ov, 0x2f, 0x80) < 0) goto error;
 
-	if (ov518_init_compression(ov511)) goto error;
+	if (ov518_init_compression(ov)) goto error;
 
-	ov511_set_packet_size(ov511, 0);
+	ov51x_set_packet_size(ov, 0);
 
-	ov511->snap_enabled = snapshot;
+	ov->snap_enabled = snapshot;
 
 	/* Test for 76xx */
-	ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID;
-	if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID,
-				OV7xx0_I2C_READ_ID) < 0)
+	ov->primary_i2c_slave = OV7xx0_SID;
+	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
 		goto error;
 
 	/* The OV518 must be more aggressive about sensor detection since
 	 * I2C write will never fail if the sensor is not present. We have
 	 * to try to initialize the sensor to detect its presence */
 
-	if (ov51x_init_ov_sensor(ov511) < 0) {
+	if (init_ov_sensor(ov) < 0) {
 		/* Test for 6xx0 */
-		ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID;
-		if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID,
-					OV6xx0_I2C_READ_ID) < 0)
+		ov->primary_i2c_slave = OV6xx0_SID;
+		if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
 			goto error;
 
-		if (ov51x_init_ov_sensor(ov511) < 0) {
+		if (init_ov_sensor(ov) < 0) {
 			/* Test for 8xx0 */
-			ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID;
-			if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID,
-						OV8xx0_I2C_READ_ID) < 0)
+			ov->primary_i2c_slave = OV8xx0_SID;
+			if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
 				goto error;
 
-			if (ov51x_init_ov_sensor(ov511) < 0) {
+			if (init_ov_sensor(ov) < 0) {
 				err("Can't determine sensor slave IDs");
  				goto error;
 			} else {
@@ -6659,21 +6565,25 @@
 				goto error;
 			}
 		} else {
-			if (ov6xx0_configure(ov511) < 0) {
+			if (ov6xx0_configure(ov) < 0) {
 				err("Failed to configure OV6xx0");
  				goto error;
 			}
 		}
 	} else {
-		if (ov7xx0_configure(ov511) < 0) {
+		if (ov7xx0_configure(ov) < 0) {
 			err("Failed to configure OV7xx0");
 	 		goto error;
 		}
 	}
 
+	// FIXME: Sizes > 320x240 are not working yet
+	ov->maxwidth = 320;
+	ov->maxheight = 240;
+
 	// The OV518 cannot go as low as the sensor can
-	ov511->minwidth = 160;
-	ov511->minheight = 120;
+	ov->minwidth = 160;
+	ov->minheight = 120;
 
 	return 0;
 
@@ -6695,7 +6605,7 @@
 	    const struct usb_device_id *id)
 {
 	struct usb_interface_descriptor *interface;
-	struct usb_ov511 *ov511;
+	struct usb_ov511 *ov;
 	int i;
 	int registered = 0;
 
@@ -6716,54 +6626,54 @@
 	/* Since code below may sleep, we use this as a lock */
 	MOD_INC_USE_COUNT;
 
-	if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
-		err("couldn't kmalloc ov511 struct");
-		goto error_unlock;
-	}
-
-	memset(ov511, 0, sizeof(*ov511));
-
-	ov511->dev = dev;
-	ov511->iface = interface->bInterfaceNumber;
-	ov511->led_policy = led;
-	ov511->compress = compress;
-	ov511->lightfreq = lightfreq;
-	ov511->num_inputs = 1;	   /* Video decoder init functs. change this */
-	ov511->stop_during_set = !fastset;
-	ov511->tuner_type = tuner;
-	ov511->backlight = backlight;
-
-	ov511->auto_brt = autobright;
-	ov511->auto_gain = autogain;
-	ov511->auto_exp = autoexp;
+	if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+		err("couldn't kmalloc ov struct");
+		goto error_out;
+	}
+
+	memset(ov, 0, sizeof(*ov));
+
+	ov->dev = dev;
+	ov->iface = interface->bInterfaceNumber;
+	ov->led_policy = led;
+	ov->compress = compress;
+	ov->lightfreq = lightfreq;
+	ov->num_inputs = 1;	   /* Video decoder init functs. change this */
+	ov->stop_during_set = !fastset;
+	ov->tuner_type = tuner;
+	ov->backlight = backlight;
+
+	ov->auto_brt = autobright;
+	ov->auto_gain = autogain;
+	ov->auto_exp = autoexp;
 
 	switch (dev->descriptor.idProduct) {
 	case PROD_OV511:
 		info("USB OV511 camera found");
-		ov511->bridge = BRG_OV511;
-		ov511->bclass = BCL_OV511;
+		ov->bridge = BRG_OV511;
+		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV511PLUS:
 		info("USB OV511+ camera found");
-		ov511->bridge = BRG_OV511PLUS;
-		ov511->bclass = BCL_OV511;
+		ov->bridge = BRG_OV511PLUS;
+		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV518:
 		info("USB OV518 camera found");
-		ov511->bridge = BRG_OV518;
-		ov511->bclass = BCL_OV518;
+		ov->bridge = BRG_OV518;
+		ov->bclass = BCL_OV518;
 		break;
 	case PROD_OV518PLUS:
 		info("USB OV518+ camera found");
-		ov511->bridge = BRG_OV518PLUS;
-		ov511->bclass = BCL_OV518;
+		ov->bridge = BRG_OV518PLUS;
+		ov->bclass = BCL_OV518;
 		break;
 	case PROD_ME2CAM:
 		if (dev->descriptor.idVendor != VEND_MATTEL)
 			goto error;
 		info("Intel Play Me2Cam (OV511+) found");
-		ov511->bridge = BRG_OV511PLUS;
-		ov511->bclass = BCL_OV511;
+		ov->bridge = BRG_OV511PLUS;
+		ov->bclass = BCL_OV511;
 		break;
 	default:
 		err("Unknown product ID 0x%x", dev->descriptor.idProduct);
@@ -6775,47 +6685,53 @@
 	if (force_rgb)
 		info("data format set to RGB");
 
-	init_waitqueue_head(&ov511->wq);
+	init_waitqueue_head(&ov->wq);
 
-	init_MUTEX(&ov511->lock);	/* to 1 == available */
-	init_MUTEX(&ov511->buf_lock);
-	init_MUTEX(&ov511->param_lock);
-	init_MUTEX(&ov511->i2c_lock);
-	ov511->buf_state = BUF_NOT_ALLOCATED;
-
-	if (ov511->bridge == BRG_OV518 ||
-	    ov511->bridge == BRG_OV518PLUS) {
-		if (ov518_configure(ov511) < 0)
+	init_MUTEX(&ov->lock);	/* to 1 == available */
+	init_MUTEX(&ov->buf_lock);
+	init_MUTEX(&ov->param_lock);
+	init_MUTEX(&ov->i2c_lock);
+	init_MUTEX(&ov->cbuf_lock);
+
+	ov->buf_state = BUF_NOT_ALLOCATED;
+
+	/* Must be kmalloc()'ed, for DMA accessibility */
+	ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
+	if (!ov->cbuf)
+		goto error;
+
+	if (ov->bclass == BCL_OV518) {
+		if (ov518_configure(ov) < 0)
 			goto error;
 	} else {
-		if (ov511_configure(ov511) < 0)
+		if (ov511_configure(ov) < 0)
 			goto error;
 	}
 
 	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov511->frame[i].framenum = i;
-		init_waitqueue_head(&ov511->frame[i].wq);
+		ov->frame[i].framenum = i;
+		init_waitqueue_head(&ov->frame[i].wq);
 	}
 
 	/* Unnecessary? (This is done on open(). Need to make sure variables
 	 * are properly initialized without this before removing it, though). */
-	if (ov51x_set_default_params(ov511) < 0)
+	if (ov51x_set_default_params(ov) < 0)
 		goto error;
 
 #ifdef OV511_DEBUG
 	if (dump_bridge)
-		ov511_dump_regs(dev);
+		ov511_dump_regs(ov);
 #endif
 
-	memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
-	ov511->vdev.priv = ov511;
+	memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template));
+	ov->vdev.priv = ov;
 
 	for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
 		/* Minor 0 cannot be specified; assume user wants autodetect */
 		if (unit_video[i] == 0)
 			break;
 
-		if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER,
+		if (video_register_device(&ov->vdev, VFL_TYPE_GRABBER,
 			unit_video[i]) >= 0) {
 			registered = 1;
 			break;
@@ -6824,34 +6740,41 @@
 
 	/* Use the next available one */
 	if (!registered &&
-	    video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+	    video_register_device(&ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
 		err("video_register_device failed");
 		goto error;
 	}
 
-	info("Device registered on minor %d", ov511->vdev.minor);
+	info("Device registered on minor %d", ov->vdev.minor);
 
 	MOD_DEC_USE_COUNT;
-     	return ov511;
+     	return ov;
 
 error:
 	err("Camera initialization failed");
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	/* Safe to call even if entry doesn't exist */
-	destroy_proc_ov511_cam(ov511);
+	destroy_proc_ov511_cam(ov);
 #endif
 
+	if (ov->cbuf) {
+		down(&ov->cbuf_lock);
+		kfree(ov->cbuf);
+		ov->cbuf = NULL;
+		up(&ov->cbuf_lock);
+	}
+
 	usb_driver_release_interface(&ov511_driver,
-		&dev->actconfig->interface[ov511->iface]);
+		&dev->actconfig->interface[ov->iface]);
 
 error_dealloc:
-	if (ov511) {
-		kfree(ov511);
-		ov511 = NULL;
+	if (ov) {
+		kfree(ov);
+		ov = NULL;
 	}
 
-error_unlock:
+error_out:
 	MOD_DEC_USE_COUNT;
 	return NULL;
 }
@@ -6860,7 +6783,7 @@
 static void
 ov51x_disconnect(struct usb_device *dev, void *ptr)
 {
-	struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
+	struct usb_ov511 *ov = (struct usb_ov511 *) ptr;
 	int n;
 
 	MOD_INC_USE_COUNT;
@@ -6868,48 +6791,53 @@
 	PDEBUG(3, "");
 
 	/* We don't want people trying to open up the device */
-	if (!ov511->user)
-		video_unregister_device(&ov511->vdev);
+	if (!ov->user)
+		video_unregister_device(&ov->vdev);
 	else
 		PDEBUG(3, "Device open...deferring video_unregister_device");
 
 	for (n = 0; n < OV511_NUMFRAMES; n++)
-		ov511->frame[n].grabstate = FRAME_ERROR;
+		ov->frame[n].grabstate = FRAME_ERROR;
 
-	ov511->curframe = -1;
+	ov->curframe = -1;
 
 	/* This will cause the process to request another frame */
 	for (n = 0; n < OV511_NUMFRAMES; n++)
-		if (waitqueue_active(&ov511->frame[n].wq))
-			wake_up_interruptible(&ov511->frame[n].wq);
-	if (waitqueue_active(&ov511->wq))
-		wake_up_interruptible(&ov511->wq);
+		if (waitqueue_active(&ov->frame[n].wq))
+			wake_up_interruptible(&ov->frame[n].wq);
+	if (waitqueue_active(&ov->wq))
+		wake_up_interruptible(&ov->wq);
 
-	ov511->streaming = 0;
+	ov->streaming = 0;
 
 	/* Unschedule all of the iso td's */
 	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov511->sbuf[n].urb) {
-			ov511->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov511->sbuf[n].urb);
-			usb_free_urb(ov511->sbuf[n].urb);
-			ov511->sbuf[n].urb = NULL;
+		if (ov->sbuf[n].urb) {
+			ov->sbuf[n].urb->next = NULL;
+			usb_unlink_urb(ov->sbuf[n].urb);
+			usb_free_urb(ov->sbuf[n].urb);
+			ov->sbuf[n].urb = NULL;
 		}
 	}
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-        destroy_proc_ov511_cam(ov511);
+        destroy_proc_ov511_cam(ov);
 #endif
 
 	usb_driver_release_interface(&ov511_driver,
-		&ov511->dev->actconfig->interface[ov511->iface]);
-	ov511->dev = NULL;
+		&ov->dev->actconfig->interface[ov->iface]);
+	ov->dev = NULL;
 
 	/* Free the memory */
-	if (ov511 && !ov511->user) {
-		ov511_dealloc(ov511, 1);
-		kfree(ov511);
-		ov511 = NULL;
+	if (ov && !ov->user) {
+		down(&ov->cbuf_lock);
+		kfree(ov->cbuf);
+		ov->cbuf = NULL;
+		up(&ov->cbuf_lock);
+
+		ov51x_dealloc(ov, 1);
+		kfree(ov);
+		ov = NULL;
 	}
 
 	MOD_DEC_USE_COUNT;
diff -urN linux-2.4.19-pre2/drivers/usb/ov511.h linux-2.4.19-pre3/drivers/usb/ov511.h
--- linux-2.4.19-pre2/drivers/usb/ov511.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/ov511.h	Mon Mar 11 14:13:29 2002
@@ -9,11 +9,11 @@
 #define OV511_DEBUG	/* Turn on debug messages */
 
 #ifdef OV511_DEBUG
-#  define PDEBUG(level, fmt, args...) \
-if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \
-	## args)
+	#define PDEBUG(level, fmt, args...) \
+		if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\
+		__LINE__ , ## args)
 #else
-#  define PDEBUG(level, fmt, args...) do {} while(0)
+	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
 
 /* This macro restricts an int variable to an inclusive range */
@@ -36,98 +36,105 @@
 #define VEND_MATTEL	0x0813
 #define PROD_ME2CAM	0x0002
 
+/* --------------------------------- */
+/*     OV51x REGISTER MNEMONICS      */
+/* --------------------------------- */
+
 /* Camera interface register numbers */
-#define OV511_REG_CAMERA_DELAY_MODE		0x10
-#define OV511_REG_CAMERA_EDGE_MODE		0x11
-#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM	0x12
-#define OV511_REG_CAMERA_CLAMPED_LINE_NUM	0x13
-#define OV511_REG_CAMERA_PIXEL_DIVISOR		0x14
-#define OV511_REG_CAMERA_LINE_DIVISOR		0x15
-#define OV511_REG_CAMERA_DATA_INPUT_SELECT	0x16
-#define OV511_REG_CAMERA_RESERVED_LINE_MODE	0x17
-#define OV511_REG_CAMERA_BITMASK		0x18
+#define R511_CAM_DELAY		0x10
+#define R511_CAM_EDGE		0x11
+#define R511_CAM_PXCNT		0x12
+#define R511_CAM_LNCNT		0x13
+#define R511_CAM_PXDIV		0x14
+#define R511_CAM_LNDIV		0x15
+#define R511_CAM_UV_EN		0x16
+#define R511_CAM_LINE_MODE	0x17
+#define R511_CAM_OPTS		0x18
 
 /* Snapshot mode camera interface register numbers */
-#define OV511_REG_SNAP_CAPTURED_FRAME		0x19
-#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM	0x1A
-#define OV511_REG_SNAP_CLAMPED_LINE_NUM		0x1B
-#define OV511_REG_SNAP_PIXEL_DIVISOR		0x1C
-#define OV511_REG_SNAP_LINE_DIVISOR		0x1D
-#define OV511_REG_SNAP_DATA_INPUT_SELECT	0x1E
-#define OV511_REG_SNAP_BITMASK			0x1F
+#define R511_SNAP_FRAME		0x19
+#define R511_SNAP_PXCNT		0x1A
+#define R511_SNAP_LNCNT		0x1B
+#define R511_SNAP_PXDIV		0x1C
+#define R511_SNAP_LNDIV		0x1D
+#define R511_SNAP_UV_EN		0x1E
+#define R511_SNAP_OPTS		0x1F
 
 /* DRAM register numbers */
-#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL	0x20
-#define OV511_REG_DRAM_READ_CYCLE_PREDICT	0x21
-#define OV511_REG_DRAM_MANUAL_READ_CYCLE	0x22
-#define OV511_REG_DRAM_REFRESH_COUNTER		0x23
+#define R511_DRAM_FLOW_CTL	0x20
+#define R511_DRAM_ARCP		0x21
+#define R511_DRAM_MRC		0x22
+#define R511_DRAM_RFC		0x23
 
 /* ISO FIFO register numbers */
-#define OV511_REG_FIFO_PACKET_SIZE		0x30
-#define OV511_REG_FIFO_BITMASK			0x31
+#define R51x_FIFO_PSIZE		0x30	/* 2 bytes wide w/ OV518(+) */
+#define R511_FIFO_OPTS		0x31
 
-/* PIO register numbers */
-#define OV511_REG_PIO_BITMASK			0x38
-#define OV511_REG_PIO_DATA_PORT			0x39
-#define OV511_REG_PIO_BIST			0x3E
-
-/* I2C register numbers */
-#define OV511_REG_I2C_CONTROL			0x40
-#define OV518_REG_I2C_CONTROL			0x47	/* OV518(+) only */
-#define OV511_REG_I2C_SLAVE_ID_WRITE		0x41
-#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE	0x42
-#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE	0x43
-#define OV511_REG_I2C_SLAVE_ID_READ		0x44
-#define OV511_REG_I2C_DATA_PORT			0x45
-#define OV511_REG_I2C_CLOCK_PRESCALER		0x46
-#define OV511_REG_I2C_TIME_OUT_COUNTER		0x47
-
-/* I2C snapshot register numbers */
-#define OV511_REG_I2C_SNAP_SUB_ADDRESS		0x48
-#define OV511_REG_I2C_SNAP_DATA_PORT		0x49
-
-/* System control register numbers */
-#define OV511_REG_SYSTEM_RESET			0x50
-#define 	OV511_RESET_UDC			0x01
-#define 	OV511_RESET_I2C			0x02
-#define 	OV511_RESET_FIFO		0x04
-#define 	OV511_RESET_OMNICE		0x08
-#define 	OV511_RESET_DRAM_INTF		0x10
-#define 	OV511_RESET_CAMERA_INTF		0x20
-#define 	OV511_RESET_OV511		0x40
-#define 	OV511_RESET_NOREGS		0x3F /* All but OV511 & regs */
-#define 	OV511_RESET_ALL			0x7F
-#define OV511_REG_SYSTEM_CLOCK_DIVISOR		0x51
-#define OV511_REG_SYSTEM_SNAPSHOT		0x52
-#define OV511_REG_SYSTEM_INIT         		0x53
-#define OV511_REG_SYSTEM_PWR_CLK		0x54 /* OV511+/OV518(+) only */
-#define OV511_REG_SYSTEM_LED_CTL		0x55	/* OV511+ only */
-#define OV518_REG_GPIO_IN			0x55	/* OV518(+) only */
-#define OV518_REG_GPIO_OUT			0x56	/* OV518(+) only */
-#define OV518_REG_GPIO_CTL			0x57	/* OV518(+) only */
-#define OV518_REG_GPIO_PULSE_IN			0x58	/* OV518(+) only */
-#define OV518_REG_GPIO_PULSE_CLEAR		0x59	/* OV518(+) only */
-#define OV518_REG_GPIO_PULSE_POLARITY		0x5a	/* OV518(+) only */
-#define OV518_REG_GPIO_PULSE_EN			0x5b	/* OV518(+) only */
-#define OV518_REG_GPIO_RESET			0x5c	/* OV518(+) only */
-#define OV511_REG_SYSTEM_USER_DEFINED		0x5E
-#define OV511_REG_SYSTEM_CUSTOM_ID		0x5F
-
-/* OmniCE register numbers */
-#define OV511_OMNICE_PREDICTION_HORIZ_Y		0x70
-#define OV511_OMNICE_PREDICTION_HORIZ_UV	0x71
-#define OV511_OMNICE_PREDICTION_VERT_Y		0x72
-#define OV511_OMNICE_PREDICTION_VERT_UV		0x73
-#define OV511_OMNICE_QUANTIZATION_HORIZ_Y	0x74
-#define OV511_OMNICE_QUANTIZATION_HORIZ_UV	0x75
-#define OV511_OMNICE_QUANTIZATION_VERT_Y	0x76
-#define OV511_OMNICE_QUANTIZATION_VERT_UV	0x77
-#define OV511_OMNICE_ENABLE			0x78
-#define OV511_OMNICE_LUT_ENABLE			0x79		
-#define OV511_OMNICE_Y_LUT_BEGIN		0x80
-#define OV511_OMNICE_Y_LUT_END			0x9F
-#define OV511_OMNICE_UV_LUT_BEGIN		0xA0
-#define OV511_OMNICE_UV_LUT_END			0xBF
+/* Parallel IO register numbers */
+#define R511_PIO_OPTS		0x38
+#define R511_PIO_DATA		0x39
+#define R511_PIO_BIST		0x3E
+#define R518_GPIO_IN		0x55	/* OV518(+) only */
+#define R518_GPIO_OUT		0x56	/* OV518(+) only */
+#define R518_GPIO_CTL		0x57	/* OV518(+) only */
+#define R518_GPIO_PULSE_IN	0x58	/* OV518(+) only */
+#define R518_GPIO_PULSE_CLEAR	0x59	/* OV518(+) only */
+#define R518_GPIO_PULSE_POL	0x5a	/* OV518(+) only */
+#define R518_GPIO_PULSE_EN	0x5b	/* OV518(+) only */
+#define R518_GPIO_RESET		0x5c	/* OV518(+) only */
+
+/* I2C registers */
+#define R511_I2C_CTL		0x40
+#define R518_I2C_CTL		0x47	/* OV518(+) only */
+#define R51x_I2C_W_SID		0x41
+#define R51x_I2C_SADDR_3	0x42
+#define R51x_I2C_SADDR_2	0x43
+#define R51x_I2C_R_SID		0x44
+#define R51x_I2C_DATA		0x45
+#define R51x_I2C_CLOCK		0x46
+#define R51x_I2C_TIMEOUT	0x47
+
+/* I2C snapshot registers */
+#define R511_SI2C_SADDR_3	0x48
+#define R511_SI2C_DATA		0x49
+
+/* System control registers */
+#define R51x_SYS_RESET		0x50
+		/* Reset type definitions */
+#define 	OV511_RESET_UDC		0x01
+#define 	OV511_RESET_I2C		0x02
+#define 	OV511_RESET_FIFO	0x04
+#define 	OV511_RESET_OMNICE	0x08
+#define 	OV511_RESET_DRAM	0x10
+#define 	OV511_RESET_CAM_INT	0x20
+#define 	OV511_RESET_OV511	0x40
+#define 	OV511_RESET_NOREGS	0x3F /* All but OV511 & regs */
+#define 	OV511_RESET_ALL		0x7F
+
+#define R511_SYS_CLOCK_DIV	0x51
+#define R51x_SYS_SNAP		0x52
+#define R51x_SYS_INIT         	0x53
+#define R511_SYS_PWR_CLK	0x54 /* OV511+/OV518(+) only */
+#define R511_SYS_LED_CTL	0x55 /* OV511+ only */
+#define R511_SYS_USER		0x5E
+#define R511_SYS_CUST_ID	0x5F
+
+/* OmniCE (compression) registers */
+#define R511_COMP_PHY		0x70
+#define R511_COMP_PHUV		0x71
+#define R511_COMP_PVY		0x72
+#define R511_COMP_PVUV		0x73
+#define R511_COMP_QHY		0x74
+#define R511_COMP_QHUV		0x75
+#define R511_COMP_QVY		0x76
+#define R511_COMP_QVUV		0x77
+#define R511_COMP_EN		0x78
+#define R511_COMP_LUT_EN	0x79		
+#define R511_COMP_LUT_BEGIN	0x80
+
+/* --------------------------------- */
+/*         ALTERNATE NUMBERS         */
+/* --------------------------------- */
 
 /* Alternate numbers for various max packet sizes (OV511 only) */
 #define OV511_ALT_SIZE_992	0
@@ -159,6 +166,10 @@
 #define OV518_ALT_SIZE_768	6
 #define OV518_ALT_SIZE_896	7
 
+/* --------------------------------- */
+/*     OV7610 REGISTER MNEMONICS     */
+/* --------------------------------- */
+
 /* OV7610 registers */
 #define OV7610_REG_GAIN          0x00	/* gain setting (5:0) */
 #define OV7610_REG_BLUE          0x01	/* blue channel balance */
@@ -210,26 +221,27 @@
 					/* 36-37 reserved */
 #define OV7610_REG_COM_K         0x38	/* misc registers */
 
+/* --------------------------------- */
+/*           I2C ADDRESSES           */
+/* --------------------------------- */
+
+#define OV7xx0_SID   0x42
+#define OV6xx0_SID   0xC0
+#define OV8xx0_SID   0xA0
+#define KS0127_SID   0xD8
+#define SAA7111A_SID 0x48
+
+/* --------------------------------- */
+/*       MISCELLANEOUS DEFINES       */
+/* --------------------------------- */
+
+#define I2C_CLOCK_PRESCALER 	0x03
+
 #define FRAMES_PER_DESC		10	/* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC	993	/* FIXME - Deprecated */
 #define MAX_FRAME_SIZE_PER_DESC	993	/* For statically allocated stuff */
 #define PIXELS_PER_SEG		256	/* Pixels per segment */
 
-#define OV511_ENDPOINT_ADDRESS 1	/* Isoc endpoint number */
-
-/* I2C addresses */
-#define OV7xx0_I2C_WRITE_ID   0x42
-#define OV7xx0_I2C_READ_ID    0x43
-#define OV6xx0_I2C_WRITE_ID   0xC0
-#define OV6xx0_I2C_READ_ID    0xC1
-#define OV8xx0_I2C_WRITE_ID   0xA0
-#define OV8xx0_I2C_READ_ID    0xA1
-#define KS0127_I2C_WRITE_ID   0xD8
-#define KS0127_I2C_READ_ID    0xD9
-#define SAA7111A_I2C_WRITE_ID 0x48
-#define SAA7111A_I2C_READ_ID  0x49
-
-#define OV511_I2C_CLOCK_PRESCALER 0x03
+#define OV511_ENDPOINT_ADDRESS	1	/* Isoc endpoint number */
 
 /* Bridge types */
 enum {
@@ -366,7 +378,7 @@
 
 struct ov511_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 enum {
@@ -429,11 +441,14 @@
 
 #define OV511_NUMFRAMES	2
 #if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-#error "OV511_NUMFRAMES is too high"
+	#error "OV511_NUMFRAMES is too high"
 #endif
 
 #define OV511_NUMSBUF		2
 
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE		4
+
 struct usb_ov511 {
 	struct video_device vdev;
 
@@ -535,6 +550,10 @@
 	/* I2C interface to kernel */
 	struct semaphore i2c_lock;	  /* Protect I2C controller regs */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
+
+	/* Control transaction stuff */
+	unsigned char *cbuf;		/* Buffer for payload */
+	struct semaphore cbuf_lock;
 };
 
 struct cam_list {
diff -urN linux-2.4.19-pre2/drivers/usb/pegasus.h linux-2.4.19-pre3/drivers/usb/pegasus.h
--- linux-2.4.19-pre2/drivers/usb/pegasus.h	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/usb/pegasus.h	Mon Mar 11 14:13:29 2002
@@ -145,6 +145,7 @@
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
+#define	VENDOR_SIEMENS		0x067c
 
 
 #else	/* PEGASUS_DEV */
@@ -173,6 +174,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II ) 	
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
@@ -245,6 +248,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
+		DEFAULT_GPIO_RESET )
 
 
 #endif	/* PEGASUS_DEV */
diff -urN linux-2.4.19-pre2/drivers/usb/serial/cyberjack.c linux-2.4.19-pre3/drivers/usb/serial/cyberjack.c
--- linux-2.4.19-pre2/drivers/usb/serial/cyberjack.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/usb/serial/cyberjack.c	Mon Mar 11 14:13:29 2002
@@ -238,13 +238,16 @@
 	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
 		/* To much data  for buffer. Reset buffer. */
 		priv->wrfilled=0;
+		up (&port->sem);
 		return (0);
 	}
 
 	/* Copy data */
 	if (from_user) {
-		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count))
+		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
+			up (&port->sem);
 			return -EFAULT;
+		}
 	} else {
 		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
 	}  
diff -urN linux-2.4.19-pre2/drivers/usb/serial/ftdi_sio.c linux-2.4.19-pre3/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.19-pre2/drivers/usb/serial/ftdi_sio.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre3/drivers/usb/serial/ftdi_sio.c	Mon Mar 11 14:13:30 2002
@@ -138,6 +138,7 @@
    
 static __devinitdata struct usb_device_id id_table_8U232AM [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
 
@@ -145,6 +146,7 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
 
diff -urN linux-2.4.19-pre2/drivers/usb/serial/ftdi_sio.h linux-2.4.19-pre3/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.19-pre2/drivers/usb/serial/ftdi_sio.h	Thu May 24 14:55:51 2001
+++ linux-2.4.19-pre3/drivers/usb/serial/ftdi_sio.h	Mon Mar 11 14:13:30 2002
@@ -22,6 +22,8 @@
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
+#define FTDI_NF_RIC_PID	0x0001	/* Product Id */
 
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff -urN linux-2.4.19-pre2/drivers/usb/serial/ipaq.c linux-2.4.19-pre3/drivers/usb/serial/ipaq.c
--- linux-2.4.19-pre2/drivers/usb/serial/ipaq.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/serial/ipaq.c	Mon Mar 11 14:13:30 2002
@@ -1,7 +1,7 @@
 /*
  * USB Compaq iPAQ driver
  *
- *	Copyright (C) 2001
+ *	Copyright (C) 2001 - 2002
  *	    Ganesh Varadarajan <ganesh@veritas.com>
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -9,6 +9,9 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (25/2/2002) ganesh
+ * 	Added support for the HP Jornada 548 and 568. Completely untested.
+ * 	Thanks to info from Heath Robinson and Arieh Davidoff.
  */
 
 #include <linux/config.h>
@@ -39,9 +42,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.1"
+#define DRIVER_VERSION "v0.2"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
-#define DRIVER_DESC "USB Compaq iPAQ driver"
+#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver"
 
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -61,7 +64,9 @@
 
 
 static __devinitdata struct usb_device_id ipaq_id_table [] = {
-	{ USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
+	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -71,10 +76,10 @@
 struct usb_serial_device_type ipaq_device = {
 	name:			"Compaq iPAQ",
 	id_table:		ipaq_id_table,
-	needs_interrupt_in:	MUST_HAVE_NOT,
+	needs_interrupt_in:	DONT_CARE,
 	needs_bulk_in:		MUST_HAVE,
 	needs_bulk_out:		MUST_HAVE,
-	num_interrupt_in:	0,
+	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
 	num_ports:		1,
diff -urN linux-2.4.19-pre2/drivers/usb/serial/ipaq.h linux-2.4.19-pre3/drivers/usb/serial/ipaq.h
--- linux-2.4.19-pre2/drivers/usb/serial/ipaq.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/serial/ipaq.h	Mon Mar 11 14:13:30 2002
@@ -1,7 +1,7 @@
 /*
  * USB Compaq iPAQ driver
  *
- *	Copyright (C) 2001
+ *	Copyright (C) 2001 - 2002
  *	    Ganesh Varadarajan <ganesh@veritas.com>
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -16,8 +16,12 @@
 #define __LINUX_USB_SERIAL_IPAQ_H
 
 
-#define IPAQ_VENDOR_ID			0x049f
-#define IPAQ_PRODUCT_ID			0x0003
+#define COMPAQ_VENDOR_ID	0x049f
+#define COMPAQ_IPAQ_ID		0x0003
+
+#define HP_VENDOR_ID		0x003f
+#define HP_JORNADA_548_ID	0x1016
+#define HP_JORNADA_568_ID	0x1116
 
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
diff -urN linux-2.4.19-pre2/drivers/usb/storage/datafab.c linux-2.4.19-pre3/drivers/usb/storage/datafab.c
--- linux-2.4.19-pre2/drivers/usb/storage/datafab.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/datafab.c	Mon Mar 11 14:13:30 2002
@@ -1,16 +1,25 @@
 /* Driver for Datafab USB Compact Flash reader
  *
+ * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
+ *
  * datafab driver v0.1:
  *
  * First release
  *
  * Current development and maintenance by:
  *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
- *   many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
  *   which I used as a template for this driver.
+ *
  *   Some bugfixes and scatter-gather code by Gregory P. Smith 
  *   (greg-usb@electricrain.com)
  *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Other contributors:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2, or (at your option) any
@@ -102,7 +111,7 @@
 	if (result == -EPIPE) {
 		US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for"
 			  " pipe 0x%x, stalled at %d bytes\n", pipe, act_len);
-		usb_clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us, pipe);
 	}
 
 	if (result) {
@@ -801,6 +810,23 @@
 		return USB_STOR_TRANSPORT_GOOD;
 	}
 
+	if (srb->cmnd[0] == START_STOP) {
+		/* this is used by sd.c'check_scsidisk_media_change to detect
+		   media change */
+		US_DEBUGP("datafab_transport:  START_STOP.\n");
+		/* the first datafab_id_device after a media change returns
+		   an error (determined experimentally) */
+		rc = datafab_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = CHECK_CONDITION;
+		}
+		return rc;
+        }
+
 	US_DEBUGP("datafab_transport:  Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
 	return USB_STOR_TRANSPORT_ERROR;
 }
diff -urN linux-2.4.19-pre2/drivers/usb/storage/debug.c linux-2.4.19-pre3/drivers/usb/storage/debug.c
--- linux-2.4.19-pre2/drivers/usb/storage/debug.c	Sun Jul 29 21:11:50 2001
+++ linux-2.4.19-pre3/drivers/usb/storage/debug.c	Mon Mar 11 14:13:30 2002
@@ -1,10 +1,13 @@
 /* Driver for USB Mass Storage compliant devices
  * Debugging Functions Source Code File
  *
- * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $
+ * $Id: debug.c,v 1.8 2002/02/25 00:40:13 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -300,9 +303,11 @@
 	case 0x1902: what="defect list error in primary list"; break;
 	case 0x1903: what="defect list error in grown list"; break;
 	case 0x1C00: what="defect list not found"; break;
+	case 0x2000: what="invalid command operation code"; break;
 	case 0x2400: what="invalid field in CDB"; break;
 	case 0x2703: what="associated write protect"; break;
 	case 0x2800: what="not ready to ready transition"; break;
+	case 0x2900: what="device reset occurred"; break;
 	case 0x2903: what="bus device reset function occurred"; break;
 	case 0x2904: what="device internal reset"; break;
 	case 0x2B00: what="copy can't execute / host can't disconnect"; break;
@@ -325,6 +330,7 @@
 	case 0x3502: what="enclosure services unavailable"; break;
 	case 0x3503: what="enclosure services transfer failure"; break;
 	case 0x3504: what="enclosure services transfer refused"; break;
+	case 0x3A00: what="media not present"; break;
 	case 0x3B0F: what="end of medium reached"; break;
 	case 0x3F02: what="changed operating definition"; break;
 	case 0x4100: what="data path failure (should use 40 NN)"; break;
diff -urN linux-2.4.19-pre2/drivers/usb/storage/isd200.c linux-2.4.19-pre3/drivers/usb/storage/isd200.c
--- linux-2.4.19-pre2/drivers/usb/storage/isd200.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/isd200.c	Mon Mar 11 14:13:30 2002
@@ -1,9 +1,15 @@
 /* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
  *
- * First release
+ * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $
  *
- * Current development and maintenance by:
- *   (c) 2000 In-System Design, Inc. (support@in-system.com)
+ * Current development and maintenance:
+ *   (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
+ *
+ * Developed with the assistance of:
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work:
+ *   (C) 2000 In-System Design, Inc. (support@in-system.com)
  *
  * The ISD200 ASIC does not natively support ATA devices.  The chip
  * does implement an interface, the ATA Command Block (ATACB) which provides
@@ -27,6 +33,10 @@
  *
  *  2001-02-24: Removed lots of duplicate code and simplified the structure.
  *              (bjorn@haxx.se)
+ *  2002-01-16: Fixed endianness bug so it works on the ppc arch.
+ *              (Luc Saillard <luc@saillard.org>)
+ *  2002-01-17: All bitfields removed.
+ *              (bjorn@haxx.se)
  */
 
 
@@ -45,15 +55,6 @@
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 
-/*
- * Inquiry defines. Used to interpret data returned from target as result
- * of inquiry command.
- *
- * DeviceType field
- */
-
-#define DIRECT_ACCESS_DEVICE            0x00    /* disks */
-
 /* Timeout defines (in Seconds) */
 
 #define ISD200_ENUM_BSY_TIMEOUT         35
@@ -88,6 +89,19 @@
 #define ACTION_SELECT_6             0x40
 #define ACTION_SELECT_7             0x80
 
+/* Register Select bits */
+#define REG_ALTERNATE_STATUS 0x01
+#define REG_DEVICE_CONTROL   0x01
+#define REG_ERROR            0x02
+#define REG_FEATURES         0x02
+#define REG_SECTOR_COUNT     0x04
+#define REG_SECTOR_NUMBER    0x08
+#define REG_CYLINDER_LOW     0x10
+#define REG_CYLINDER_HIGH    0x20
+#define REG_DEVICE_HEAD      0x40
+#define REG_STATUS           0x80
+#define REG_COMMAND          0x80
+
 /* ATA error definitions not in <linux/hdreg.h> */
 #define ATA_ERROR_MEDIA_CHANGE       0x20
 
@@ -152,20 +166,8 @@
 	struct {
 		unsigned char SignatureByte0;
 		unsigned char SignatureByte1;
-		unsigned char ReadRegisterAccessBit : 1;
-		unsigned char NoDeviceSelectionBit : 1;
-		unsigned char NoBSYPollBit : 1;
-		unsigned char IgnorePhaseErrorBit : 1;
-		unsigned char IgnoreDeviceErrorBit : 1;
-		unsigned char Reserved0Bit : 3;
-		unsigned char SelectAlternateStatus : 1;
-		unsigned char SelectError : 1;
-		unsigned char SelectSectorCount : 1;
-		unsigned char SelectSectorNumber : 1;
-		unsigned char SelectCylinderLow : 1;
-		unsigned char SelectCylinderHigh : 1;
-		unsigned char SelectDeviceHead : 1;
-		unsigned char SelectStatus : 1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
 		unsigned char TransferBlockSize;
 		unsigned char AlternateStatusByte;
 		unsigned char ErrorByte;
@@ -181,20 +183,8 @@
         struct {
 		unsigned char SignatureByte0;
 		unsigned char SignatureByte1;
-		unsigned char ReadRegisterAccessBit : 1;
-		unsigned char NoDeviceSelectionBit : 1;
-		unsigned char NoBSYPollBit : 1;
-		unsigned char IgnorePhaseErrorBit : 1;
-		unsigned char IgnoreDeviceErrorBit : 1;
-		unsigned char Reserved0Bit : 3;
-		unsigned char SelectDeviceControl : 1;
-		unsigned char SelectFeatures : 1;
-		unsigned char SelectSectorCount : 1;
-		unsigned char SelectSectorNumber : 1;
-		unsigned char SelectCylinderLow : 1;
-		unsigned char SelectCylinderHigh : 1;
-		unsigned char SelectDeviceHead : 1;
-		unsigned char SelectCommand : 1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
 		unsigned char TransferBlockSize;
 		unsigned char DeviceControlByte;
 		unsigned char FeaturesByte;
@@ -218,27 +208,20 @@
  * includes fields through ProductRevisionLevel.
  */
 
+/*
+ * DeviceType field
+ */
+#define DIRECT_ACCESS_DEVICE            0x00    /* disks */
+#define DEVICE_REMOVABLE                0x80
+
 struct inquiry_data {
-	unsigned char DeviceType : 5;
-	unsigned char DeviceTypeQualifier : 3;
-	unsigned char DeviceTypeModifier : 7;
-	unsigned char RemovableMedia : 1;
+   	unsigned char DeviceType;
+	unsigned char DeviceTypeModifier;
 	unsigned char Versions;
-	unsigned char ResponseDataFormat : 4;
-	unsigned char HiSupport : 1;
-	unsigned char NormACA : 1;
-	unsigned char ReservedBit : 1;
-	unsigned char AERC : 1;
+	unsigned char Format; 
 	unsigned char AdditionalLength;
 	unsigned char Reserved[2];
-	unsigned char SoftReset : 1;
-	unsigned char CommandQueue : 1;
-	unsigned char Reserved2 : 1;
-	unsigned char LinkedCommands : 1;
-	unsigned char Synchronous : 1;
-	unsigned char Wide16Bit : 1;
-	unsigned char Wide32Bit : 1;
-	unsigned char RelativeAddressing : 1;
+	unsigned char Capability;
 	unsigned char VendorId[8];
 	unsigned char ProductId[16];
 	unsigned char ProductRevisionLevel[4];
@@ -257,25 +240,30 @@
  * ISD200 CONFIG data struct
  */
 
+#define ATACFG_TIMING          0x0f
+#define ATACFG_ATAPI_RESET     0x10
+#define ATACFG_MASTER          0x20
+#define ATACFG_BLOCKSIZE       0xa0
+
+#define ATACFGE_LAST_LUN       0x07
+#define ATACFGE_DESC_OVERRIDE  0x08
+#define ATACFGE_STATE_SUSPEND  0x10
+#define ATACFGE_SKIP_BOOT      0x20
+#define ATACFGE_CONF_DESC2     0x40
+#define ATACFGE_INIT_STATUS    0x80
+
+#define CFG_CAPABILITY_SRST    0x01
+
 struct isd200_config {
         unsigned char EventNotification;
         unsigned char ExternalClock;
         unsigned char ATAInitTimeout;
-        unsigned char ATATiming : 4;
-        unsigned char ATAPIReset : 1;
-        unsigned char MasterSlaveSelection : 1;
-        unsigned char ATAPICommandBlockSize : 2;
+	unsigned char ATAConfig;
         unsigned char ATAMajorCommand;
         unsigned char ATAMinorCommand;
-        unsigned char LastLUNIdentifier : 3;
-        unsigned char DescriptOverride : 1;
-        unsigned char ATA3StateSuspend : 1;
-        unsigned char SkipDeviceBoot : 1;
-        unsigned char ConfigDescriptor2 : 1;
-        unsigned char InitStatus : 1;
-        unsigned char SRSTEnable : 1;
-        unsigned char Reserved0 : 7;
-};
+	unsigned char ATAExtraConfig;
+	unsigned char Capability;
+}__attribute__ ((packed));
 
 
 /*
@@ -321,15 +309,16 @@
  * Sense Data Format
  */
 
+#define SENSE_ERRCODE           0x7f
+#define SENSE_ERRCODE_VALID     0x80
+#define SENSE_FLAG_SENSE_KEY    0x0f
+#define SENSE_FLAG_BAD_LENGTH   0x20
+#define SENSE_FLAG_END_OF_MEDIA 0x40
+#define SENSE_FLAG_FILE_MARK    0x80
 struct sense_data {
-        unsigned char ErrorCode:7;
-        unsigned char Valid:1;
-        unsigned char SegmentNumber;
-        unsigned char SenseKey:4;
-        unsigned char Reserved:1;
-        unsigned char IncorrectLength:1;
-        unsigned char EndOfMedia:1;
-        unsigned char FileMark:1;
+	unsigned char ErrorCode;
+	unsigned char SegmentNumber;
+	unsigned char Flags;
         unsigned char Information[4];
         unsigned char AdditionalSenseLength;
         unsigned char CommandSpecificInformation[4];
@@ -349,7 +338,6 @@
  * Helper routines
  ***********************************************************************/
 
-
 /**************************************************************************
  * isd200_build_sense
  *                                                                         
@@ -366,38 +354,33 @@
         unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
 
 	if(error & ATA_ERROR_MEDIA_CHANGE) {
-		buf->ErrorCode = 0x70;
-		buf->Valid     = 1;
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
-		buf->SenseKey =  UNIT_ATTENTION;
+		buf->Flags = UNIT_ATTENTION;
 		buf->AdditionalSenseCode = 0;
 		buf->AdditionalSenseCodeQualifier = 0;
         } else if(error & MCR_ERR) {
-		buf->ErrorCode = 0x70;
-		buf->Valid     = 1;
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
-		buf->SenseKey =  UNIT_ATTENTION;
+		buf->Flags =  UNIT_ATTENTION;
 		buf->AdditionalSenseCode = 0;
 		buf->AdditionalSenseCodeQualifier = 0;
         } else if(error & TRK0_ERR) {
-		buf->ErrorCode = 0x70;
-		buf->Valid     = 1;
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
-		buf->SenseKey =  NOT_READY;
+		buf->Flags =  NOT_READY;
 		buf->AdditionalSenseCode = 0;
 		buf->AdditionalSenseCodeQualifier = 0;
         } else if(error & ECC_ERR) {
-		buf->ErrorCode = 0x70;
-		buf->Valid     = 1;
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
-		buf->SenseKey =  DATA_PROTECT;
+		buf->Flags =  DATA_PROTECT;
 		buf->AdditionalSenseCode = 0;
 		buf->AdditionalSenseCodeQualifier = 0;
         } else {
 		buf->ErrorCode = 0;
-		buf->Valid     = 0;
 		buf->AdditionalSenseLength = 0;
-		buf->SenseKey =  0;
+		buf->Flags =  0;
 		buf->AdditionalSenseCode = 0;
 		buf->AdditionalSenseCodeQualifier = 0;
         }
@@ -442,7 +425,7 @@
         /* if we stall, we need to clear it before we go on */
         if (result == -EPIPE) {
                 US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                usb_stor_clear_halt(us->pusb_dev, pipe);
+                usb_stor_clear_halt(us, pipe);
         }
     
         /* did we send all the data? */
@@ -593,7 +576,7 @@
         US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
                   le32_to_cpu(bcb.Signature), bcb.Tag,
                   (bcb.Lun >> 4), (bcb.Lun & 0xFF), 
-                  bcb.DataTransferLength, bcb.Flags, bcb.Length);
+                  le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
         result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
 				   &partial);
         US_DEBUGP("Bulk command transfer result=%d\n", result);
@@ -603,7 +586,7 @@
 	else if (result == -EPIPE) {
 		/* if we stall, we need to clear it before we go on */
                 US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                usb_stor_clear_halt(us->pusb_dev, pipe);
+                usb_stor_clear_halt(us, pipe);
 	} else if (result)  
                 return ISD200_TRANSPORT_ERROR;
     
@@ -633,7 +616,7 @@
         /* did the attempt to read the CSW fail? */
         if (result == -EPIPE) {
                 US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                usb_stor_clear_halt(us->pusb_dev, pipe);
+                usb_stor_clear_halt(us, pipe);
            
                 /* get the status again */
                 US_DEBUGP("Attempting to get CSW (2nd try)...\n");
@@ -647,7 +630,7 @@
                 /* if it fails again, we need a reset and return an error*/
                 if (result == -EPIPE) {
                         US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
-                        usb_stor_clear_halt(us->pusb_dev, pipe);
+                        usb_stor_clear_halt(us, pipe);
                         return ISD200_TRANSPORT_ERROR;
                 }
         }
@@ -716,10 +699,9 @@
 	case ACTION_READ_STATUS:
 		US_DEBUGP("   isd200_action(READ_STATUS)\n");
 		ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
-		ata.read.SelectStatus = 1;
-		ata.read.SelectError = 1;
-		ata.read.SelectCylinderHigh = 1;
-		ata.read.SelectCylinderLow = 1;
+		ata.generic.RegisterSelect =
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_STATUS | REG_ERROR;
 		srb.sc_data_direction = SCSI_DATA_READ;
 		srb.request_buffer = pointer;
 		srb.request_bufflen = value;
@@ -730,7 +712,7 @@
 		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
 			                   ACTION_SELECT_3|ACTION_SELECT_4|
 		                           ACTION_SELECT_5;
-		ata.write.SelectDeviceHead = 1;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
 		ata.write.DeviceHeadByte = value;
 		srb.sc_data_direction = SCSI_DATA_NONE;
 		break;
@@ -739,7 +721,7 @@
 		US_DEBUGP("   isd200_action(RESET)\n");
 		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
 			                   ACTION_SELECT_3|ACTION_SELECT_4;
-		ata.write.SelectDeviceControl = 1;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
 		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
 		srb.sc_data_direction = SCSI_DATA_NONE;
 		break;
@@ -748,7 +730,7 @@
 		US_DEBUGP("   isd200_action(REENABLE)\n");
 		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
 			                   ACTION_SELECT_3|ACTION_SELECT_4;
-		ata.write.SelectDeviceControl = 1;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
 		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
 		srb.sc_data_direction = SCSI_DATA_NONE;
 		break;
@@ -756,16 +738,15 @@
 	case ACTION_SOFT_RESET:
 		US_DEBUGP("   isd200_action(SOFT_RESET)\n");
 		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
-		ata.write.SelectDeviceHead = 1;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
 		ata.write.DeviceHeadByte = info->DeviceHead;
-		ata.write.SelectCommand = 1;
 		ata.write.CommandByte = WIN_SRST;
 		srb.sc_data_direction = SCSI_DATA_NONE;
 		break;
 
 	case ACTION_IDENTIFY:
 		US_DEBUGP("   isd200_action(IDENTIFY)\n");
-		ata.write.SelectCommand = 1;
+		ata.generic.RegisterSelect = REG_COMMAND;
 		ata.write.CommandByte = WIN_IDENTIFY;
 		srb.sc_data_direction = SCSI_DATA_READ;
 		srb.request_buffer = (void *)&info->drive;
@@ -886,6 +867,43 @@
 		srb->result = CHECK_CONDITION;
 }
 
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void isd200_log_config( struct isd200_info* info )
+{
+	US_DEBUGP("      Event Notification: 0x%x\n", 
+		  info->ConfigData.EventNotification);
+	US_DEBUGP("      External Clock: 0x%x\n", 
+		  info->ConfigData.ExternalClock);
+	US_DEBUGP("      ATA Init Timeout: 0x%x\n", 
+		  info->ConfigData.ATAInitTimeout);
+	US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", 
+		  (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
+	US_DEBUGP("      Master/Slave Selection: 0x%x\n", 
+		  info->ConfigData.ATAConfig & ATACFG_MASTER);
+	US_DEBUGP("      ATAPI Reset: 0x%x\n",
+		  info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
+	US_DEBUGP("      ATA Timing: 0x%x\n",
+		  info->ConfigData.ATAConfig & ATACFG_TIMING);
+	US_DEBUGP("      ATA Major Command: 0x%x\n", 
+		  info->ConfigData.ATAMajorCommand);
+	US_DEBUGP("      ATA Minor Command: 0x%x\n", 
+		  info->ConfigData.ATAMinorCommand);
+	US_DEBUGP("      Init Status: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
+	US_DEBUGP("      Config Descriptor 2: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
+	US_DEBUGP("      Skip Device Boot: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
+	US_DEBUGP("      ATA 3 State Supsend: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
+	US_DEBUGP("      Descriptor Override: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
+	US_DEBUGP("      Last LUN Identifier: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
+	US_DEBUGP("      SRST Enable: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
+}
+#endif
 
 /**************************************************************************
  * isd200_write_config
@@ -901,26 +919,11 @@
 	int retStatus = ISD200_GOOD;
 	int result;
 
-
+#ifdef CONFIG_USB_STORAGE_DEBUG
 	US_DEBUGP("Entering isd200_write_config\n");
-
 	US_DEBUGP("   Writing the following ISD200 Config Data:\n");
-	US_DEBUGP("      Event Notification: 0x%x\n", info->ConfigData.EventNotification);
-	US_DEBUGP("      External Clock: 0x%x\n", info->ConfigData.ExternalClock);
-	US_DEBUGP("      ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout);
-	US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize);
-	US_DEBUGP("      Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection);
-	US_DEBUGP("      ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset);
-	US_DEBUGP("      ATA Timing: 0x%x\n", info->ConfigData.ATATiming);
-	US_DEBUGP("      ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand);
-	US_DEBUGP("      ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand);
-	US_DEBUGP("      Init Status: 0x%x\n", info->ConfigData.InitStatus);
-	US_DEBUGP("      Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2);
-	US_DEBUGP("      Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot);
-	US_DEBUGP("      ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend);
-	US_DEBUGP("      Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride);
-	US_DEBUGP("      Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier);
-	US_DEBUGP("      SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable);
+	isd200_log_config(info);
+#endif
 
 	/* let's send the command via the control pipe */
 	result = usb_stor_control_msg(
@@ -941,8 +944,8 @@
 		/* STALL must be cleared when they are detected */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_stor_clear_halt(us->pusb_dev,
-						     usb_sndctrlpipe(us->pusb_dev, 0));
+			result = usb_stor_clear_halt(us,
+					usb_sndctrlpipe(us->pusb_dev, 0));
 			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 
 		}
@@ -986,30 +989,17 @@
 
 	if (result >= 0) {
 		US_DEBUGP("   Retrieved the following ISD200 Config Data:\n");
-		US_DEBUGP("      Event Notification: 0x%x\n", info->ConfigData.EventNotification);
-		US_DEBUGP("      External Clock: 0x%x\n", info->ConfigData.ExternalClock);
-		US_DEBUGP("      ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout);
-		US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize);
-		US_DEBUGP("      Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection);
-		US_DEBUGP("      ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset);
-		US_DEBUGP("      ATA Timing: 0x%x\n", info->ConfigData.ATATiming);
-		US_DEBUGP("      ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand);
-		US_DEBUGP("      ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand);
-		US_DEBUGP("      Init Status: 0x%x\n", info->ConfigData.InitStatus);
-		US_DEBUGP("      Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2);
-		US_DEBUGP("      Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot);
-		US_DEBUGP("      ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend);
-		US_DEBUGP("      Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride);
-		US_DEBUGP("      Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier);
-		US_DEBUGP("      SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable);
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		isd200_log_config(info);
+#endif
         } else {
 		US_DEBUGP("   Request to get ISD200 Config Data failed!\n");
 
 		/* STALL must be cleared when they are detected */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_stor_clear_halt(us->pusb_dev,   
-						     usb_sndctrlpipe(us->pusb_dev, 0));
+			result = usb_stor_clear_halt(us,   
+					usb_sndctrlpipe(us->pusb_dev, 0));
 			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 
 		}
@@ -1175,11 +1165,12 @@
 				break;
 			}
 		} else {
-			US_DEBUGP("   Not ATA, not ATAPI. Weird.\n");
+ 			US_DEBUGP("   Not ATA, not ATAPI. Weird.\n");
+			break;
 		}
 
 		/* check for timeout on this request */
-		if (jiffies >= endTime) {
+		if (time_after_eq(jiffies, endTime)) {
 			if (!detect)
 				US_DEBUGP("   BSY check timeout, just continue with next operation...\n");
 			else
@@ -1223,9 +1214,10 @@
 		}
 
 		isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
-		if (info->ConfigData.MasterSlaveSelection != isslave) {
+		if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) {
 			US_DEBUGP("   Setting Master/Slave selection to %d\n", isslave);
-			info->ConfigData.MasterSlaveSelection = isslave;
+			info->ConfigData.ATAConfig &= 0x3f;
+			info->ConfigData.ATAConfig |= (isslave<<6);
 			retStatus = isd200_write_config(us);
 		}
 	}
@@ -1272,6 +1264,8 @@
 			} else {
 				/* ATA Command Identify successful */
 				int i;
+				__u16 *src, *dest;
+				ide_fix_driveid(&info->drive);
 
 				US_DEBUGP("   Identify Data Structure:\n");
 				US_DEBUGP("      config = 0x%x\n", info->drive.config);
@@ -1317,31 +1311,25 @@
 
 				if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) {
 					/* set the removable bit */
-					info->InquiryData.RemovableMedia = 1;
+					info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
 					info->DeviceFlags |= DF_REMOVABLE_MEDIA;
 				}
 
 				/* Fill in vendor identification fields */
-				for (i = 0; i < 20; i += 2) {
-					info->InquiryData.VendorId[i] = 
-						info->drive.model[i + 1];
-					info->InquiryData.VendorId[i+1] = 
-						info->drive.model[i];
-				}
-
-				/* Initialize unused portion of product id */
-				for (i = 0; i < 4; i++) {
-					info->InquiryData.ProductId[12+i] = ' ';
-				}
-
-				/* Move firmware revision from IDENTIFY data to */
-				/* product revision in INQUIRY data             */
-				for (i = 0; i < 4; i += 2) {
-					info->InquiryData.ProductRevisionLevel[i] =
-						info->drive.fw_rev[i+1];
-					info->InquiryData.ProductRevisionLevel[i+1] =
-						info->drive.fw_rev[i];
-				}
+				src = (__u16*)info->drive.model;
+				dest = (__u16*)info->InquiryData.VendorId;
+				for (i=0;i<4;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__u16*)(info->drive.model+8);
+				dest = (__u16*)info->InquiryData.ProductId;
+				for (i=0;i<8;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__u16*)info->drive.fw_rev;
+				dest = (__u16*)info->InquiryData.ProductRevisionLevel;
+				for (i=0;i<2;i++)
+					dest[i] = be16_to_cpu(src[i]);
 
 				/* determine if it supports Media Status Notification */
 				if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) {
@@ -1483,7 +1471,7 @@
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
-			ataCdb->write.SelectCommand = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
 			srb->request_bufflen = 0;
 		} else {
@@ -1504,7 +1492,7 @@
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
-			ataCdb->write.SelectCommand = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
 			srb->request_bufflen = 0;
 		} else {
@@ -1561,17 +1549,15 @@
 		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 		ataCdb->generic.TransferBlockSize = 1;
-		ataCdb->write.SelectSectorCount = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
 		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
-		ataCdb->write.SelectSectorNumber = 1;
 		ataCdb->write.SectorNumberByte = sectnum;
-		ataCdb->write.SelectCylinderHigh = 1;
 		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
-		ataCdb->write.SelectCylinderLow = 1;
 		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
-		ataCdb->write.SelectDeviceHead = 1;
 		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
-		ataCdb->write.SelectCommand = 1;
 		ataCdb->write.CommandByte = WIN_READ;
 		break;
 
@@ -1594,17 +1580,15 @@
 		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 		ataCdb->generic.TransferBlockSize = 1;
-		ataCdb->write.SelectSectorCount = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
 		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
-		ataCdb->write.SelectSectorNumber = 1;
 		ataCdb->write.SectorNumberByte = sectnum;
-		ataCdb->write.SelectCylinderHigh = 1;
 		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
-		ataCdb->write.SelectCylinderLow = 1;
 		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
-		ataCdb->write.SelectDeviceHead = 1;
 		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
-		ataCdb->write.SelectCommand = 1;
 		ataCdb->write.CommandByte = WIN_WRITE;
 		break;
 
@@ -1617,7 +1601,7 @@
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
-			ataCdb->write.SelectCommand = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
 				WIN_DOORLOCK : WIN_DOORUNLOCK;
 			srb->request_bufflen = 0;
@@ -1640,14 +1624,14 @@
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 0;
-			ataCdb->write.SelectCommand = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
 		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
 			US_DEBUGP("   Get Media Status\n");
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
-			ataCdb->write.SelectCommand = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
 			srb->request_bufflen = 0;
 		} else {
diff -urN linux-2.4.19-pre2/drivers/usb/storage/jumpshot.c linux-2.4.19-pre3/drivers/usb/storage/jumpshot.c
--- linux-2.4.19-pre2/drivers/usb/storage/jumpshot.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/jumpshot.c	Mon Mar 11 14:13:30 2002
@@ -1,16 +1,26 @@
 /* Driver for Lexar "Jumpshot" Compact Flash reader
  *
+ * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
+ *
  * jumpshot driver v0.1:
  *
  * First release
  *
  * Current development and maintenance by:
  *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
- *   many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
  *   which I used as a template for this driver.
+ *
  *   Some bugfixes and scatter-gather code by Gregory P. Smith 
  *   (greg-usb@electricrain.com)
  *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Developed with the assistance of:
+ *
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2, or (at your option) any
@@ -128,8 +138,8 @@
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("jumpshot_send_control:  -- Stall on control pipe. Clearing\n");
-			result = usb_clear_halt(us->pusb_dev, pipe);
-			US_DEBUGP("jumpshot_send_control:  -- usb_clear_halt() returns %d\n", result);
+			result = usb_stor_clear_halt(us, pipe);
+			US_DEBUGP("jumpshot_send_control:  -- usb_stor_clear_halt() returns %d\n", result);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -161,7 +171,7 @@
 	if (result == -EPIPE) {
 		US_DEBUGP("jumpshot_raw_bulk:  EPIPE. clearing endpoint halt for"
 			  " pipe 0x%x, stalled at %d bytes\n", pipe, act_len);
-		usb_clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us, pipe);
 	}
 
 	if (result) {
@@ -798,6 +808,23 @@
 		//
 		return USB_STOR_TRANSPORT_GOOD;
 	}
+	
+	if (srb->cmnd[0] == START_STOP) {
+		/* this is used by sd.c'check_scsidisk_media_change to detect
+		   media change */
+		US_DEBUGP("jumpshot_transport:  START_STOP.\n");
+		/* the first jumpshot_id_device after a media change returns
+		   an error (determined experimentally) */
+		rc = jumpshot_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = CHECK_CONDITION;
+		}
+		return rc;
+        }
 
 	US_DEBUGP("jumpshot_transport:  Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
 	return USB_STOR_TRANSPORT_ERROR;
diff -urN linux-2.4.19-pre2/drivers/usb/storage/protocol.c linux-2.4.19-pre3/drivers/usb/storage/protocol.c
--- linux-2.4.19-pre2/drivers/usb/storage/protocol.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/protocol.c	Mon Mar 11 14:13:30 2002
@@ -1,12 +1,13 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
+ * $Id: protocol.c,v 1.13 2002/02/25 00:34:56 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2002 Alan Stern (stern@rowland.org)
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -97,9 +98,11 @@
 
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
+	if (srb->result == GOOD << 1) {
 
-	/* fix the INQUIRY data if necessary */
-	fix_inquiry_data(srb);
+		/* fix the INQUIRY data if necessary */
+		fix_inquiry_data(srb);
+	}
 }
 
 void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
@@ -168,13 +171,15 @@
 
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
+	if (srb->result == GOOD << 1) {
 
-	/* Fix the MODE_SENSE data if we translated the command */
-	if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD))
-		usb_stor_scsiSense10to6(srb);
-
-	/* fix the INQUIRY data if necessary */
-	fix_inquiry_data(srb);
+		/* Fix the MODE_SENSE data if we translated the command */
+		if (old_cmnd == MODE_SENSE)
+			usb_stor_scsiSense10to6(srb);
+
+		/* fix the INQUIRY data if necessary */
+		fix_inquiry_data(srb);
+	}
 }
 
 
@@ -263,13 +268,15 @@
 
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
+	if (srb->result == GOOD << 1) {
 
-	/* Fix the MODE_SENSE data if we translated the command */
-	if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD))
-		usb_stor_scsiSense10to6(srb);
-
-	/* Fix the data for an INQUIRY, if necessary */
-	fix_inquiry_data(srb);
+		/* Fix the MODE_SENSE data if we translated the command */
+		if (old_cmnd == MODE_SENSE)
+			usb_stor_scsiSense10to6(srb);
+
+		/* Fix the data for an INQUIRY, if necessary */
+		fix_inquiry_data(srb);
+	}
 }
 
 void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
@@ -330,13 +337,14 @@
 
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
+	if (srb->result == GOOD << 1) {
 
-	/* Fix the MODE_SENSE data if we translated the command */
-	if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)
-			&& (status_byte(srb->result) == GOOD))
-		usb_stor_scsiSense10to6(srb);
-
-	/* fix the INQUIRY data if necessary */
-	fix_inquiry_data(srb);
+		/* Fix the MODE_SENSE data if we translated the command */
+		if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE))
+			usb_stor_scsiSense10to6(srb);
+
+		/* fix the INQUIRY data if necessary */
+		fix_inquiry_data(srb);
+	}
 }
 
diff -urN linux-2.4.19-pre2/drivers/usb/storage/sddr09.c linux-2.4.19-pre3/drivers/usb/storage/sddr09.c
--- linux-2.4.19-pre2/drivers/usb/storage/sddr09.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/sddr09.c	Mon Mar 11 14:13:30 2002
@@ -1,6 +1,6 @@
 /* Driver for SanDisk SDDR-09 SmartMedia reader
  *
- * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $
+ * $Id: sddr09.c,v 1.23 2002/02/25 00:40:13 mdharm Exp $
  *
  * SDDR09 driver v0.1:
  *
@@ -9,6 +9,9 @@
  * Current development and maintenance by:
  *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
  *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
  * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
  * This chip is a programmable USB controller. In the SDDR-09, it has
  * been programmed to obey a certain limited set of SCSI commands. This
@@ -113,8 +116,8 @@
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_clear_halt(us->pusb_dev, pipe);
-			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			result = usb_stor_clear_halt(us, pipe);
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -146,7 +149,7 @@
        	        US_DEBUGP("EPIPE: clearing endpoint halt for"
 			" pipe 0x%x, stalled at %d bytes\n",
 			pipe, act_len);
-               	usb_clear_halt(us->pusb_dev, pipe);
+               	usb_stor_clear_halt(us, pipe);
         }
 
 	if (result) {
diff -urN linux-2.4.19-pre2/drivers/usb/storage/shuttle_usbat.c linux-2.4.19-pre3/drivers/usb/storage/shuttle_usbat.c
--- linux-2.4.19-pre2/drivers/usb/storage/shuttle_usbat.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/shuttle_usbat.c	Mon Mar 11 14:13:30 2002
@@ -1,10 +1,13 @@
 /* Driver for SCM Microsystems USB-ATAPI cable
  *
- * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $
+ * $Id: shuttle_usbat.c,v 1.16 2002/02/25 00:40:13 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
  *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
  * Many originally ATAPI devices were slightly modified to meet the USB
  * market by using some kind of translation from ATAPI to USB on the host,
  * and the peripheral would translate from USB back to ATAPI.
@@ -107,8 +110,8 @@
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_clear_halt(us->pusb_dev, pipe);
-			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			result = usb_stor_clear_halt(us, pipe);
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -140,7 +143,7 @@
        	        US_DEBUGP("EPIPE: clearing endpoint halt for"
 			" pipe 0x%x, stalled at %d bytes\n",
 			pipe, act_len);
-               	usb_clear_halt(us->pusb_dev, pipe);
+               	usb_stor_clear_halt(us, pipe);
         }
 
 	if (result) {
@@ -515,7 +518,7 @@
 			 */
 
 			if (direction==SCSI_DATA_READ && i==0)
-				usb_clear_halt(us->pusb_dev,
+				usb_stor_clear_halt(us,
 					usb_sndbulkpipe(us->pusb_dev,
 					  us->ep_out));
 			/*
@@ -675,9 +678,15 @@
 		len = short_pack(data[7+9], data[7+8]);
 		len <<= 16;
 		len |= data[7+7];
+		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
 		srb->transfersize = srb->request_bufflen/len;
 	}
 
+	if (!srb->transfersize)  {
+		srb->transfersize = 2048; /* A guess */
+		US_DEBUGP("handle_read10: transfersize 0, forcing %d\n",
+			srb->transfersize);
+	}
 
 	len = (65535/srb->transfersize) * srb->transfersize;
 	US_DEBUGP("Max read is %d bytes\n", len);
diff -urN linux-2.4.19-pre2/drivers/usb/storage/transport.c linux-2.4.19-pre3/drivers/usb/storage/transport.c
--- linux-2.4.19-pre2/drivers/usb/storage/transport.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/transport.c	Mon Mar 11 14:13:30 2002
@@ -1,13 +1,14 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $
+ * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
  *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ *   (c) 2002 Alan Stern <stern@rowland.org>
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -335,31 +336,7 @@
 			   len = srb->request_bufflen;
 	   }
 
-return len;
-}
-
-/* This is a version of usb_clear_halt() that doesn't read the status from
- * the device -- this is because some devices crash their internal firmware
- * when the status is requested after a halt
- */
-int usb_stor_clear_halt(struct usb_device *dev, int pipe)
-{
-	int result;
-	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
-
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
-				 endp, NULL, 0, HZ * 3);
-
-	/* this is a failure case */
-	if (result < 0)
-		return result;
-
-	/* reset the toggles and endpoint flags */
-	usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
-	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
-
-	return 0;
+	return len;
 }
 
 /***********************************************************************
@@ -481,6 +458,34 @@
 	return us->current_urb->status;
 }
 
+/* This is a version of usb_clear_halt() that doesn't read the status from
+ * the device -- this is because some devices crash their internal firmware
+ * when the status is requested after a halt
+ */
+int usb_stor_clear_halt(struct us_data *us, int pipe)
+{
+	int result;
+	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
+
+	result = usb_stor_control_msg(us,
+		usb_sndctrlpipe(us->pusb_dev, 0),
+		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+		endp, NULL, 0);		/* note: no 3*HZ timeout */
+	US_DEBUGP("usb_stor_clear_halt: result=%d\n", result);
+
+	/* this is a failure case */
+	if (result < 0)
+		return result;
+
+	/* reset the toggles and endpoint flags */
+	usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
+		usb_pipeout(pipe));
+	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+		usb_pipeout(pipe), 0);
+
+	return 0;
+}
+
 /*
  * Transfer one SCSI scatter-gather buffer via bulk transfer
  *
@@ -513,7 +518,13 @@
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_stor_clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us, pipe);
+	}
+
+	/* did we abort this command? */
+	if (result == -ENOENT) {
+		US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
+		return US_BULK_TRANSFER_ABORTED;
 	}
 
 	/* did we send all the data? */
@@ -522,21 +533,14 @@
 		return US_BULK_TRANSFER_GOOD;
 	}
 
-	/* uh oh... we have an error code, so something went wrong. */
-	if (result) {
-		/* NAK - that means we've retried a few times already */
-		if (result == -ETIMEDOUT) {
-			US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
-			return US_BULK_TRANSFER_FAILED;
-		}
-
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
-			US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
-			return US_BULK_TRANSFER_ABORTED;
-		}
+	/* NAK - that means we've retried a few times already */
+	if (result == -ETIMEDOUT) {
+		US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
+		return US_BULK_TRANSFER_FAILED;
+	}
 
-		/* the catch-all case */
+	/* the catch-all error case */
+	if (result) {
 		US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
 		return US_BULK_TRANSFER_FAILED;
 	}
@@ -550,7 +554,7 @@
  * Transfer an entire SCSI command's worth of data payload over the bulk
  * pipe.
  *
- * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this
+ * Note that this uses usb_stor_transfer_partial to achieve its goals -- this
  * function simply determines if we're going to use scatter-gather or not,
  * and acts appropriately.  For now, it also re-interprets the error codes.
  */
@@ -631,6 +635,14 @@
 		return;
 	}
 
+	/* if there is a transport error, reset and don't auto-sense */
+	if (result == USB_STOR_TRANSPORT_ERROR) {
+		US_DEBUGP("-- transport indicates error, resetting\n");
+		us->transport_reset(us);
+		srb->result = DID_ERROR << 16;
+		return;
+	}
+
 	/* Determine if we need to auto-sense
 	 *
 	 * I normally don't use a flag like this, but it's almost impossible
@@ -660,7 +672,7 @@
 	}
 
 	/*
-	 * If we have an error, we're going to do a REQUEST_SENSE 
+	 * If we have a failure, we're going to do a REQUEST_SENSE 
 	 * automatically.  Note that we differentiate between a command
 	 * "failure" and an "error" in the transport mechanism.
 	 */
@@ -668,13 +680,6 @@
 		US_DEBUGP("-- transport indicates command failure\n");
 		need_auto_sense = 1;
 	}
-	if (result == USB_STOR_TRANSPORT_ERROR) {
-		us->transport_reset(us);
-		US_DEBUGP("-- transport indicates transport failure\n");
-		need_auto_sense = 0;
-		srb->result = DID_ERROR << 16;
-		return;
-	}
 
 	/*
 	 * Also, if we have a short transfer on a command that can't have
@@ -730,6 +735,19 @@
 
 		/* issue the auto-sense command */
 		temp_result = us->transport(us->srb, us);
+
+		/* let's clean up right away */
+		srb->request_buffer = old_request_buffer;
+		srb->request_bufflen = old_request_bufflen;
+		srb->use_sg = old_sg;
+		srb->sc_data_direction = old_sc_data_direction;
+		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+
+		if (temp_result == USB_STOR_TRANSPORT_ABORTED) {
+			US_DEBUGP("-- auto-sense aborted\n");
+			srb->result = DID_ABORT << 16;
+			return;
+		}
 		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
 			US_DEBUGP("-- auto-sense failure\n");
 
@@ -760,13 +778,6 @@
 		/* set the result so the higher layers expect this data */
 		srb->result = CHECK_CONDITION << 1;
 
-		/* we're done here, let's clean up */
-		srb->request_buffer = old_request_buffer;
-		srb->request_bufflen = old_request_bufflen;
-		srb->use_sg = old_sg;
-		srb->sc_data_direction = old_sc_data_direction;
-		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
-
 		/* If things are really okay, then let's show that */
 		if ((srb->sense_buffer[2] & 0xf) == 0x0)
 			srb->result = GOOD << 1;
@@ -864,21 +875,25 @@
 	if (result < 0) {
 		/* Reset flag for status notification */
 		atomic_set(us->ip_wanted, 0);
+	}
+
+	/* if the command was aborted, indicate that */
+	if (result == -ENOENT)
+		return USB_STOR_TRANSPORT_ABORTED;
+
+	/* STALL must be cleared when it is detected */
+	if (result == -EPIPE) {
+		US_DEBUGP("-- Stall on control pipe. Clearing\n");
+		result = usb_stor_clear_halt(us,	
+			usb_sndctrlpipe(us->pusb_dev, 0));
 
 		/* if the command was aborted, indicate that */
 		if (result == -ENOENT)
 			return USB_STOR_TRANSPORT_ABORTED;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
 
-		/* STALL must be cleared when they are detected */
-		if (result == -EPIPE) {
-			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_stor_clear_halt(us->pusb_dev,	
-					    usb_sndctrlpipe(us->pusb_dev,
-							    0));
-			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
-			return USB_STOR_TRANSPORT_FAILED;
-		}
-
+	if (result < 0) {
 		/* Uh oh... serious problem here */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -887,12 +902,18 @@
 	/* transfer the data payload for this command, if one exists*/
 	if (usb_stor_transfer_length(srb)) {
 		usb_stor_transfer(srb, us);
-		US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+		result = srb->result;
+		US_DEBUGP("CBI data stage result is 0x%x\n", result);
 
-		/* if it was aborted, we need to indicate that */
-		if (srb->result == USB_STOR_TRANSPORT_ABORTED) {
+		/* report any errors */
+		if (result == US_BULK_TRANSFER_ABORTED) {
+			atomic_set(us->ip_wanted, 0);
 			return USB_STOR_TRANSPORT_ABORTED;
 		}
+		if (result == US_BULK_TRANSFER_FAILED) {
+			atomic_set(us->ip_wanted, 0);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
 	}
 
 	/* STATUS STAGE */
@@ -976,10 +997,12 @@
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = usb_stor_clear_halt(us->pusb_dev, 
-					    usb_sndctrlpipe(us->pusb_dev,
-							    0));
-			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
+			result = usb_stor_clear_halt(us,
+				usb_sndctrlpipe(us->pusb_dev, 0));
+
+			/* if the command was aborted, indicate that */
+			if (result == -ENOENT)
+				return USB_STOR_TRANSPORT_ABORTED;
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -991,11 +1014,16 @@
 	/* transfer the data payload for this command, if one exists*/
 	if (usb_stor_transfer_length(srb)) {
 		usb_stor_transfer(srb, us);
-		US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+		result = srb->result;
+		US_DEBUGP("CB data stage result is 0x%x\n", result);
 
-		/* if it was aborted, we need to indicate that */
-		if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+		/* report any errors */
+		if (result == US_BULK_TRANSFER_ABORTED) {
 			return USB_STOR_TRANSPORT_ABORTED;
+		}
+		if (result == US_BULK_TRANSFER_FAILED) {
+			return USB_STOR_TRANSPORT_FAILED;
+		}
 	}
 
 	/* STATUS STAGE */
@@ -1016,7 +1044,8 @@
 	int result;
 	int pipe;
 
-	/* issue the command */
+	/* issue the command -- use usb_control_msg() because
+	 *  the state machine is not yet alive */
 	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
 	result = usb_control_msg(us->pusb_dev, pipe,
 				 US_BULK_GET_MAX_LUN, 
@@ -1034,7 +1063,10 @@
 	/* if we get a STALL, clear the stall */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_stor_clear_halt(us->pusb_dev, pipe);
+
+		/* Use usb_clear_halt() because the state machine
+		 *  is not yet alive */
+		usb_clear_halt(us->pusb_dev, pipe);
 	}
 
 	/* return the default -- no LUNs */
@@ -1051,10 +1083,6 @@
 	int pipe;
 	int partial;
 
-	/* if the device was removed, then we're already reset */
-	if (!us->pusb_dev)
-		return SUCCESS;
-
 	/* set up the command wrapper */
 	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
@@ -1088,7 +1116,12 @@
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_stor_clear_halt(us->pusb_dev, pipe);
+		result = usb_stor_clear_halt(us, pipe);
+
+		/* if the command was aborted, indicate that */
+		if (result == -ENOENT)
+			return USB_STOR_TRANSPORT_ABORTED;
+		result = -EPIPE;
 	} else if (result) {
 		/* unknown error -- we've got a problem */
 		return USB_STOR_TRANSPORT_ERROR;
@@ -1099,11 +1132,11 @@
 		/* send/receive data payload, if there is any */
 		if (bcb.DataTransferLength) {
 			usb_stor_transfer(srb, us);
-			US_DEBUGP("Bulk data transfer result 0x%x\n", 
-				  srb->result);
+			result = srb->result;
+			US_DEBUGP("Bulk data transfer result 0x%x\n", result);
 
 			/* if it was aborted, we need to indicate that */
-			if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+			if (result == US_BULK_TRANSFER_ABORTED)
 				return USB_STOR_TRANSPORT_ABORTED;
 		}
 	}
@@ -1127,8 +1160,12 @@
 	/* did the attempt to read the CSW fail? */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		usb_stor_clear_halt(us->pusb_dev, pipe);
-	       
+		result = usb_stor_clear_halt(us, pipe);
+
+		/* if the command was aborted, indicate that */
+		if (result == -ENOENT)
+			return USB_STOR_TRANSPORT_ABORTED;
+
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
 		result = usb_stor_bulk_msg(us, &bcs, pipe,
@@ -1141,7 +1178,11 @@
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
 			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
-			usb_stor_clear_halt(us->pusb_dev, pipe);
+			result = usb_stor_clear_halt(us, pipe);
+
+			/* if the command was aborted, indicate that */
+			if (result == -ENOENT)
+				return USB_STOR_TRANSPORT_ABORTED;
 			return USB_STOR_TRANSPORT_ERROR;
 		}
 	}
@@ -1220,10 +1261,10 @@
 	set_current_state(TASK_RUNNING);
 
 	US_DEBUGP("CB_reset: clearing endpoint halt\n");
-	usb_stor_clear_halt(us->pusb_dev, 
-			    usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	usb_stor_clear_halt(us->pusb_dev, 
-			    usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+	usb_stor_clear_halt(us,
+			usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_stor_clear_halt(us,
+			usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 
 	US_DEBUGP("CB_reset done\n");
 	/* return a result code based on the result of the control message */
@@ -1259,10 +1300,10 @@
 	schedule_timeout(HZ*6);
 	set_current_state(TASK_RUNNING);
 
-	usb_stor_clear_halt(us->pusb_dev, 
-			    usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	usb_stor_clear_halt(us->pusb_dev, 
-			    usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+	usb_stor_clear_halt(us,
+			usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_stor_clear_halt(us,
+			usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 	US_DEBUGP("Bulk soft reset completed\n");
 	return SUCCESS;
 }
diff -urN linux-2.4.19-pre2/drivers/usb/storage/transport.h linux-2.4.19-pre3/drivers/usb/storage/transport.h
--- linux-2.4.19-pre2/drivers/usb/storage/transport.h	Thu Nov 22 11:49:34 2001
+++ linux-2.4.19-pre3/drivers/usb/storage/transport.h	Mon Mar 11 14:13:30 2002
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Transport Functions Header File
  *
- * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $
+ * $Id: transport.h,v 1.17 2002/02/25 00:43:41 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -112,7 +112,7 @@
 #define US_BULK_GET_MAX_LUN	0xfe
 
 /*
- * us_bulk_transfer() return codes
+ * usb_stor_transfer() return codes
  */
 #define US_BULK_TRANSFER_GOOD		0  /* good transfer                 */
 #define US_BULK_TRANSFER_SHORT		1  /* transfered less than expected */
@@ -151,6 +151,6 @@
 		unsigned int*);
 extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8,
 		u16, u16, void*, u16);
+extern int usb_stor_clear_halt(struct us_data*, int );
 extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*);
-extern int usb_stor_clear_halt(struct usb_device*, int );
 #endif
diff -urN linux-2.4.19-pre2/drivers/usb/storage/unusual_devs.h linux-2.4.19-pre3/drivers/usb/storage/unusual_devs.h
--- linux-2.4.19-pre2/drivers/usb/storage/unusual_devs.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/unusual_devs.h	Mon Mar 11 14:13:30 2002
@@ -1,10 +1,10 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
  *   (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
@@ -198,7 +198,7 @@
 /* This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0422, 
 		"Sony",
-		"DSC-S30/S70/S75/505V/F505", 
+		"DSC-S30/S70/S75/505V/F505/F707", 
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
 
@@ -289,9 +289,30 @@
 		"Lexar",
 		"Jumpshot USB CF Reader",
 		US_SC_SCSI, US_PR_JUMPSHOT, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 #endif
 
+/* Reported by Carlos Villegas <cav@uniscope.co.jp>
+ * This device needs an INQUIRY of exactly 36-bytes to function.
+ * That is the only reason this entry is needed.
+ */
+UNUSUAL_DEV(  0x05e3, 0x0700, 0x0000, 0xffff,
+		"SIIG",
+		"CompactFlash Card Reader",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Reported by Peter Marks <peter.marks@turner.com>
+ * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly
+ * 36 bytes of data.  No more, no less. That is the only reason this entry
+ * is needed.
+ */
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+		"EagleTec",
+		"External Hard Disk",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 UNUSUAL_DEV(  0x0644, 0x0000, 0x0100, 0x0100, 
 		"TEAC",
 		"Floppy Drive",
@@ -305,6 +326,14 @@
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
 #endif
 
+/* Submitted by kedar@centillium
+ * Needed for START_STOP flag, but that is unconfirmed */
+UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
+                "Minolta",
+                "Dimage S304",
+                US_SC_SCSI, US_PR_BULK, NULL,
+                US_FL_START_STOP ),
+
 /* Submitted by f.brugmans@hccnet.nl
  * Needed for START_STOP flag */
 UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001,
@@ -381,7 +410,7 @@
 		"Datafab",
 		"MDCFE-B USB CF Reader",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 	/*
 	 * The following Datafab-based devices may or may not work
@@ -398,38 +427,38 @@
 		"SIIG/Datafab",
 		"SIIG/Datafab Memory Stick+CF Reader/Writer",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
 		"Datafab/Unknown",
 		"Datafab-based Reader",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
 		"Datafab/Unknown",
 		"Datafab-based Reader",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
 		"PNY/Datafab",
 		"PNY/Datafab CF+SM Reader",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
 		"Simple Tech/Datafab",
 		"Simple Tech/Datafab CF+SM Reader",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 
 /* Submitted by Olaf Hering <olh@suse.de> */
 UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
 		"Datafab Systems, Inc.",
 		"USB to CF + SM Combo (LC1)",
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
-		US_FL_MODE_XLATE | US_FL_START_STOP ),
+		US_FL_MODE_XLATE ),
 #endif
 
 /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
@@ -469,6 +498,8 @@
 
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
+ * Also reported by Brian Hall <brihall@bigfoot.com>, again for flags.
+ * I also suspect this device may have a broken serial number.
  */
 UNUSUAL_DEV(  0x1065, 0x2136, 0x0000, 0x9999,
 		"CCYU TECHNOLOGY",
diff -urN linux-2.4.19-pre2/drivers/usb/storage/usb.c linux-2.4.19-pre3/drivers/usb/storage/usb.c
--- linux-2.4.19-pre2/drivers/usb/storage/usb.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/storage/usb.c	Mon Mar 11 14:13:30 2002
@@ -1,9 +1,9 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
+ * $Id: usb.c,v 1.73 2002/01/27 09:02:15 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
@@ -318,6 +318,7 @@
 	current->files = init_task.files;
 	atomic_inc(&current->files->count);
 	daemonize();
+	reparent_to_init();
 
 	/* avoid getting signals */
 	spin_lock_irq(&current->sigmask_lock);
@@ -958,6 +959,7 @@
 			ss->protocol_name = "Unknown";
 			kfree(ss->current_urb);
 			kfree(ss);
+			usb_dec_dev_use(dev);
 			return NULL;
 			break;
 		}
@@ -965,6 +967,8 @@
 
 		/* allocate an IRQ callback if one is needed */
 		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) {
+			kfree(ss->current_urb);
+			kfree(ss);
 			usb_dec_dev_use(dev);
 			return NULL;
 		}
diff -urN linux-2.4.19-pre2/drivers/usb/stv680.c linux-2.4.19-pre3/drivers/usb/stv680.c
--- linux-2.4.19-pre2/drivers/usb/stv680.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/stv680.c	Mon Mar 11 14:13:30 2002
@@ -50,6 +50,12 @@
  *                         improve quality. Got rid of green line around 
  *                         frame. Fix brightness reset when changing size 
  *                         bug. Adjusted gamma filters slightly.
+ *
+ * ver 0.25 Jan, 2002 (kjs)
+ *			   Fixed a bug in which the driver sometimes attempted
+ *			   to set to a non-supported size. This allowed
+ *			   gnomemeeting to work.
+ *			   Fixed proc entry removal bug.
  */
 
 #include <linux/config.h>
@@ -87,7 +93,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.24"
+#define DRIVER_VERSION "v0.25"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -659,7 +665,7 @@
 	if (stv680_proc_entry == NULL)
 		return;
 
-	remove_proc_entry ("stv", video_proc_entry);
+	remove_proc_entry ("stv680", video_proc_entry);
 }
 #endif				/* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
@@ -862,20 +868,23 @@
 	if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
 		width = stv680->maxwidth / 2;
 		height = stv680->maxheight / 2;
-	} else if ((width >= 158) && (width <= 166)) {
+	} else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
 		width = 160;
 		height = 120;
-	} else if ((width >= 172) && (width <= 180)) {
+	} else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
 		width = 176;
 		height = 144;
-	} else if ((width >= 318) && (width <= 350)) {
+	} else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
 		width = 320;
 		height = 240;
-	} else if ((width >= 350) && (width <= 358)) {
+	} else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
 		width = 352;
 		height = 288;
+	} else {
+		PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+		return 1;
 	}
-
+	
 	/* Stop a current stream and start it again at the new size */
 	if (wasstreaming)
 		stv680_stop_stream (stv680);
diff -urN linux-2.4.19-pre2/drivers/usb/uhci.c linux-2.4.19-pre3/drivers/usb/uhci.c
--- linux-2.4.19-pre2/drivers/usb/uhci.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/usb/uhci.c	Mon Mar 11 14:13:30 2002
@@ -57,7 +57,6 @@
 
 #include <linux/pm.h>
 
-
 /*
  * Version Information
  */
@@ -65,7 +64,6 @@
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
-
 /*
  * debug = 0, no debugging messages
  * debug = 1, dump failed URB's except for stalls
@@ -100,6 +98,7 @@
 
 /* If a transfer is still active after this much time, turn off FSBR */
 #define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
+#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
 
 #define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
 
@@ -766,7 +765,7 @@
 	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
 		urbp->fsbr = 0;
 		if (!--uhci->fsbr)
-			uhci->skel_term_qh->link = UHCI_PTR_TERM;
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
 	}
 
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
@@ -2023,6 +2022,12 @@
 		uhci_unlink_urb(u);
 	}
 
+	/* Really disable FSBR */
+	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+		uhci->fsbrtimeout = 0;
+		uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	}
+
 	/* enter global suspend if nothing connected */
 	if (!uhci->is_suspended && !ports_active(uhci))
 		suspend_hc(uhci);
diff -urN linux-2.4.19-pre2/drivers/usb/uhci.h linux-2.4.19-pre3/drivers/usb/uhci.h
--- linux-2.4.19-pre2/drivers/usb/uhci.h	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/usb/uhci.h	Mon Mar 11 14:13:30 2002
@@ -309,6 +309,7 @@
 	spinlock_t frame_list_lock;
 	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
 	int fsbr;				/* Full speed bandwidth reclamation */
+	unsigned long fsbrtimeout;		/* FSBR delay */
 	int is_suspended;
 
 	/* Main list of URB's currently controlled by this HC */
diff -urN linux-2.4.19-pre2/drivers/usb/usb-skeleton.c linux-2.4.19-pre3/drivers/usb/usb-skeleton.c
--- linux-2.4.19-pre2/drivers/usb/usb-skeleton.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/usb-skeleton.c	Mon Mar 11 14:13:30 2002
@@ -1,5 +1,5 @@
 /*
- * USB Skeleton driver - 0.6
+ * USB Skeleton driver - 0.7
  *
  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
@@ -22,6 +22,9 @@
  *
  * History:
  *
+ * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do
+ *			not have both a bulk in and bulk out endpoint.
+ *			Thanks to Holger Waechtler for the fix.
  * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect.
  *			Thanks to Pete Zaitcev for the fix.
  * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux
@@ -540,6 +543,7 @@
 		err ("Out of memory");
 		goto exit;
 	}
+	memset (dev, 0x00, sizeof (*dev));
 	minor_table[minor] = dev;
 
 	interface = &udev->actconfig->interface[ifnum];
diff -urN linux-2.4.19-pre2/drivers/usb/vicam.c linux-2.4.19-pre3/drivers/usb/vicam.c
--- linux-2.4.19-pre2/drivers/usb/vicam.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre3/drivers/usb/vicam.c	Mon Mar 11 14:13:30 2002
@@ -79,7 +79,7 @@
 static struct usb_driver vicam_driver;
 
 static char *buf, *buf2;
-static int change_pending = 0; 
+static volatile int change_pending = 0; 
 
 static int vicam_parameters(struct usb_vicam *vicam);
 
@@ -330,8 +330,14 @@
 
 static void synchronize(struct usb_vicam *vicam)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	change_pending = 1;
-	interruptible_sleep_on(&vicam->wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&vicam->wait, &wait);
+	if (change_pending)
+		schedule();
+	remove_wait_queue(&vicam->wait, &wait);
+	set_current_state(TASK_RUNNING);
 	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
 	mdelay(10);
 	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
@@ -890,13 +896,16 @@
 	vicam->win.contrast = 10;
 
 	/* FIXME */
-	if (vicam_init(vicam))
+	if (vicam_init(vicam)) {
+		kfree(vicam);
 		return NULL;
+	}
 	memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
 	memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
 	
 	if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		err("video_register_device");
+		kfree(vicam);
 		return NULL;
 	}
 
diff -urN linux-2.4.19-pre2/drivers/video/acornfb.c linux-2.4.19-pre3/drivers/video/acornfb.c
--- linux-2.4.19-pre2/drivers/video/acornfb.c	Wed Nov 14 14:52:20 2001
+++ linux-2.4.19-pre3/drivers/video/acornfb.c	Mon Mar 11 14:13:30 2002
@@ -1139,9 +1139,6 @@
 	off += start;
 	vma->vm_pgoff = off >> PAGE_SHIFT;
 
-	/* This is an IO map - tell maydump to skip this VMA */
-	vma->vm_flags |= VM_IO;
-
 #ifdef CONFIG_CPU_32
 	pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;
 #endif
diff -urN linux-2.4.19-pre2/drivers/video/fbmem.c linux-2.4.19-pre3/drivers/video/fbmem.c
--- linux-2.4.19-pre2/drivers/video/fbmem.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/video/fbmem.c	Mon Mar 11 14:13:30 2002
@@ -74,6 +74,8 @@
 extern int atyfb_setup(char*);
 extern int aty128fb_init(void);
 extern int aty128fb_setup(char*);
+extern int neofb_init(void);
+extern int neofb_setup(char*);
 extern int igafb_init(void);
 extern int igafb_setup(char*);
 extern int imsttfb_init(void);
@@ -183,6 +185,9 @@
 #ifdef CONFIG_FB_ATY128
 	{ "aty128fb", aty128fb_init, aty128fb_setup },
 #endif
+#ifdef CONFIG_FB_NEOMAGIC
+	{ "neo", neofb_init, neofb_setup },
+#endif
 #ifdef CONFIG_FB_VIRGE
 	{ "virge", virgefb_init, virgefb_setup },
 #endif
@@ -571,6 +576,8 @@
 		lock_kernel();
 		res = fb->fb_mmap(info, file, vma);
 		unlock_kernel();
+		/* This is an IO map - tell maydump to skip this VMA */
+		vma->vm_flags |= VM_IO;
 		return res;
 	}
 
@@ -604,12 +611,13 @@
 		return -EINVAL;
 	off += start;
 	vma->vm_pgoff = off >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
 #if defined(__sparc_v9__)
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 	if (io_remap_page_range(vma->vm_start, off,
 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
 		return -EAGAIN;
-	vma->vm_flags |= VM_IO;
 #else
 #if defined(__mc68000__)
 #if defined(CONFIG_SUN3)
@@ -632,8 +640,6 @@
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #elif defined(__arm__) || defined(__mips__)
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	/* This is an IO map - tell maydump to skip this VMA */
-	vma->vm_flags |= VM_IO;
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #elif defined(__ia64__)
diff -urN linux-2.4.19-pre2/drivers/video/igafb.c linux-2.4.19-pre3/drivers/video/igafb.c
--- linux-2.4.19-pre2/drivers/video/igafb.c	Wed Nov 14 14:52:20 2001
+++ linux-2.4.19-pre3/drivers/video/igafb.c	Mon Mar 11 14:13:30 2002
@@ -293,8 +293,6 @@
 	if (!map_size)
 		return -EINVAL;
 
-	vma->vm_flags |= VM_IO;
-
 	if (!fb->mmaped) {
 		int lastconsole = 0;
 
diff -urN linux-2.4.19-pre2/drivers/video/neofb.c linux-2.4.19-pre3/drivers/video/neofb.c
--- linux-2.4.19-pre2/drivers/video/neofb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/drivers/video/neofb.c	Mon Mar 11 14:13:30 2002
@@ -0,0 +1,2423 @@
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ *
+ * 0.3.2
+ *  - got rid of all floating point (dok)
+ *
+ * 0.3.1
+ *  - added module license (dok)
+ *
+ * 0.3
+ *  - hardware accelerated clear and move for 2200 and above (dok)
+ *  - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ *  - correct panning after X usage (dok)
+ *  - added module and kernel parameters (dok)
+ *  - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ *  - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "neofb.h"
+
+
+#define NEOFB_VERSION "0.3.2"
+
+/* --------------------------------------------------------------------- */
+
+static int disabled   = 0;
+static int internal   = 0;
+static int external   = 0;
+static int nostretch  = 0;
+static int nopciburst = 0;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
+MODULE_PARM(internal, "i");
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+MODULE_PARM(external, "i");
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+MODULE_PARM(nostretch, "i");
+MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM(nopciburst, "i");
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {	
+    { 320, 240, 0x40 },
+    { 300, 400, 0x42 },    
+    { 640, 400, 0x20 },
+    { 640, 480, 0x21 },
+    { 800, 600, 0x23 },
+    { 1024, 768, 0x25 },
+};
+
+static biosMode bios16[] = {
+    { 320, 200, 0x2e },
+    { 320, 240, 0x41 },
+    { 300, 400, 0x43 },
+    { 640, 480, 0x31 },
+    { 800, 600, 0x34 },
+    { 1024, 768, 0x37 },
+};
+
+static biosMode bios24[] = {
+    { 640, 480, 0x32 },
+    { 800, 600, 0x35 },
+    { 1024, 768, 0x38 }
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+    { 640, 480, 0x33 },
+    { 800, 600, 0x36 },
+    { 1024, 768, 0x39 }
+    };
+#endif
+
+static int neoFindMode (int xres, int yres, int depth)
+{
+  int xres_s;
+  int i, size;
+  biosMode *mode;
+
+  switch (depth)
+    {
+    case 8:
+      size = sizeof(bios8) / sizeof(biosMode);
+      mode = bios8;
+      break;
+    case 16:
+      size = sizeof(bios16) / sizeof(biosMode);
+      mode = bios16;
+      break;
+    case 24:
+      size = sizeof(bios24) / sizeof(biosMode);
+      mode = bios24;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+      size = sizeof(bios32) / sizeof(biosMode);
+      mode = bios32;
+      break;
+#endif
+    default:
+      return 0;
+    }
+
+  for (i = 0; i < size; i++)
+    {
+      if (xres <= mode[i].x_res)
+	{
+	  xres_s = mode[i].x_res;
+	  for (; i < size; i++)
+	    {
+	      if (mode[i].x_res != xres_s)
+		return mode[i-1].mode;
+	      if (yres <= mode[i].y_res)
+		return mode[i].mode;
+	    }
+	}
+    }
+  return mode[size - 1].mode;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle (struct neofb_info *fb)
+{
+  int waitcycles;
+
+  while (fb->neo2200->bltStat & 1)
+    waitcycles++;
+}
+
+static inline void neo2200_wait_fifo (struct neofb_info *fb,
+                                      int requested_fifo_space)
+{
+  //  ndev->neo.waitfifo_calls++;
+  //  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+  /* FIXME: does not work
+  if (neo_fifo_space < requested_fifo_space)
+    {
+      neo_fifo_waitcycles++;
+
+      while (1)
+    {
+      neo_fifo_space = (neo2200->bltStat >> 8);
+      if (neo_fifo_space >= requested_fifo_space)
+        break;
+    }
+    }
+  else
+    {
+      neo_fifo_cache_hits++;
+    }
+
+  neo_fifo_space -= requested_fifo_space;
+  */
+
+  neo2200_wait_idle (fb);
+}
+
+static inline void neo2200_accel_init (struct neofb_info        *fb,
+				       struct fb_var_screeninfo *var)
+{
+  Neo2200 *neo2200 = fb->neo2200;
+  u32 bltMod, pitch;
+
+  neo2200_wait_idle (fb);
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      bltMod = NEO_MODE1_DEPTH8;
+      pitch  = var->xres_virtual;
+      break;
+    case 15:
+    case 16:
+      bltMod = NEO_MODE1_DEPTH16;
+      pitch  = var->xres_virtual * 2;
+      break;
+    default:
+      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
+      return;
+    }
+
+  neo2200->bltStat = bltMod << 16;
+  neo2200->pitch   = (pitch << 16) | pitch;
+}
+
+static void neo2200_accel_setup (struct display *p)
+{
+  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+
+  fb->dispsw->setup(p);
+
+  neo2200_accel_init (fb, var);
+}
+
+static void
+neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long src, dst;
+  int bpp, pitch, inc_y;
+  u_int fh, fw;
+
+  if (sx != dx)
+    {
+      neo2200_wait_idle (fb);
+      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
+      return;
+    }
+
+  bpp    = (var->bits_per_pixel+7) / 8;
+  pitch  = var->xres_virtual * bpp;
+
+  fw     = fontwidth(p);
+  sx    *= fw * bpp;
+  dx    *= fw * bpp;
+  width *= fw;
+
+  fh     = fontheight(p);
+  sy    *= fh;
+  dy    *= fh;
+
+  if (sy > dy)
+    inc_y = fh;
+  else
+    {
+      inc_y  = -fh;
+      sy    += (height - 1) * fh;
+      dy    += (height - 1) * fh;
+    }
+
+  neo2200_wait_fifo (fb, 1);
+
+  /* set blt control */
+  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
+                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  while (height--)
+    {
+      src = sx + sy * pitch;
+      dst = dx + dy * pitch;
+
+      neo2200_wait_fifo (fb, 3);
+
+      neo2200->srcStart = src;
+      neo2200->dstStart = dst;
+      neo2200->xyExt = (fh << 16) | (width & 0xffff);
+
+      sy += inc_y;
+      dy += inc_y;
+    }
+}
+
+static void
+neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long dst;
+  u_int fw, fh;
+  u32 bgx = attr_bgcol_ec(p, conp);
+
+  fw = fontwidth(p);
+  fh = fontheight(p);
+
+  dst    = sx * fw + sy * var->xres_virtual * fh;
+  width  = width * fw;
+  height = height * fh;
+
+  neo2200_wait_fifo (fb, 4);
+
+  /* set blt control */
+  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
+                      NEO_BC0_SRC_IS_FG    |
+                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      neo2200->fgColor = bgx;
+      break;
+    case 16:
+      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
+      break;
+    }
+
+  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+
+  neo2200->xyExt    = (height << 16) | (width & 0xffff);
+}
+
+static void
+neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
+		    int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+neo2200_accel_putcs (struct vc_data *conp, struct display *p,
+		     const unsigned short *s, int count, int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void neo2200_accel_revc (struct display *p, int xx, int yy)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	
+  neo2200_wait_idle (fb);
+  fb->dispsw->revc (p, xx, yy);
+}
+
+static void
+neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
+			     int bottom_only)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  fb->dispsw->clear_margins (conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_neo2200_accel = {
+  setup:		neo2200_accel_setup,
+  bmove:		neo2200_accel_bmove,
+  clear:		neo2200_accel_clear,
+  putc:			neo2200_accel_putc,
+  putcs:		neo2200_accel_putcs,
+  revc:			neo2200_accel_revc,
+  clear_margins:	neo2200_accel_clear_margins,
+  fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  if (regno >= NR_PALETTE)
+    return -EINVAL;
+
+  info->palette[regno].red    = red;
+  info->palette[regno].green  = green;
+  info->palette[regno].blue   = blue;
+  info->palette[regno].transp = transp;
+
+  switch (fb->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      outb(regno, 0x3c8);
+
+      outb(red   >> 10, 0x3c9);
+      outb(green >> 10, 0x3c9);
+      outb(blue  >> 10, 0x3c9);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      if (regno < 16)
+	((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
+	                                     ((green & 0xfc00) >>  5) |
+                                             ((blue  & 0xf800) >> 11);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
+                                             ((green & 0xff00)     ) |
+	                                     ((blue  & 0xff00) >> 8);
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
+	                                     ((red    & 0xff00) <<  8) |
+                                             ((green  & 0xff00)      ) |
+	                                     ((blue   & 0xff00) >>  8);
+      break;
+#endif
+#endif
+
+    default:
+      return 1;
+    }
+
+  return 0;
+}
+
+static void vgaHWLock (void)
+{
+  /* Protect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) | 0x80);
+}
+
+static void vgaHWUnlock (void)
+{
+  /* Unprotect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
+}
+
+static void neoLock (void)
+{
+  VGAwGR (0x09, 0x00);
+  vgaHWLock();
+}
+
+static void neoUnlock (void)
+{
+  vgaHWUnlock();
+  VGAwGR (0x09, 0x26);
+}
+
+/*
+ * vgaHWSeqReset
+ *      perform a sequencer reset.
+ */
+void
+vgaHWSeqReset(int start)
+{
+  if (start)
+    VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
+  else
+    VGAwSEQ (0x00, 0x03);		/* End Reset */
+}
+
+void
+vgaHWProtect(int on)
+{
+  unsigned char tmp;
+  
+  if (on)
+    {
+      /*
+       * Turn off screen and disable sequencer.
+       */
+      tmp = VGArSEQ (0x01);
+
+      vgaHWSeqReset (1);			/* start synchronous reset */
+      VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+
+      VGAenablePalette();
+    }
+  else
+    {
+      /*
+       * Reenable sequencer, then turn on screen.
+       */
+  
+      tmp = VGArSEQ (0x01);
+
+      VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
+      vgaHWSeqReset (0);		/* clear synchronousreset */
+
+      VGAdisablePalette();
+    }
+}
+
+static void vgaHWRestore (const struct neofb_info *info,
+			  const struct neofb_par  *par)
+{
+  int i;
+
+  VGAwMISC (par->MiscOutReg);
+
+  for (i = 1; i < 5; i++)
+    VGAwSEQ (i, par->Sequencer[i]);
+  
+  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+  VGAwCR (17, par->CRTC[17] & ~0x80);
+
+  for (i = 0; i < 25; i++)
+    VGAwCR (i, par->CRTC[i]);
+
+  for (i = 0; i < 9; i++)
+    VGAwGR (i, par->Graphics[i]);
+
+  VGAenablePalette();
+
+  for (i = 0; i < 21; i++)
+    VGAwATTR (i, par->Attribute[i]);
+
+  VGAdisablePalette();
+}
+
+static void neofb_set_par (struct neofb_info       *info,
+			   const struct neofb_par  *par)
+{
+  unsigned char temp;
+  int i;
+  int clock_hi = 0;
+    
+  DBG("neofb_set_par");
+
+  neoUnlock();
+
+  vgaHWProtect (1);		/* Blank the screen */
+
+  /* linear colormap for non palettized modes */
+  switch (par->depth)
+    {
+    case 8:
+      break;
+    case 16:
+      for (i=0; i<64; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i << 1, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i << 1, 0x3c9);
+	}
+      break;
+    case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+#endif
+      for (i=0; i<256; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	}
+      break;
+    }
+    
+  /* alread unlocked above */
+  /* BOGUS  VGAwGR (0x09, 0x26);*/
+    
+  /* don't know what this is, but it's 0 from bootup anyway */
+  VGAwGR (0x15, 0x00);
+
+  /* was set to 0x01 by my bios in text and vesa modes */
+  VGAwGR (0x0A, par->GeneralLockReg);
+
+  /*
+   * The color mode needs to be set before calling vgaHWRestore
+   * to ensure the DAC is initialized properly.
+   *
+   * NOTE: Make sure we don't change bits make sure we don't change
+   * any reserved bits.
+   */
+  temp = VGArGR(0x90);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xF0; /* Save bits 7:4 */
+      temp |= (par->ExtColorModeSelect & ~0xF0);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x70; /* Save bits 6:4 */
+      temp |= (par->ExtColorModeSelect & ~0x70);
+      break;
+    }
+
+  VGAwGR(0x90,temp);
+
+  /*
+   * In some rare cases a lockup might occur if we don't delay
+   * here. (Reported by Miles Lane)
+   */
+  //mdelay(200);
+
+  /*
+   * Disable horizontal and vertical graphics and text expansions so
+   * that vgaHWRestore works properly.
+   */
+  temp = VGArGR(0x25);
+  temp &= 0x39;
+  VGAwGR (0x25, temp);
+
+  /*
+   * Sleep for 200ms to make sure that the two operations above have
+   * had time to take effect.
+   */
+  mdelay(200);
+
+  /*
+   * This function handles restoring the generic VGA registers.  */
+  vgaHWRestore (info, par);
+
+
+  VGAwGR(0x0E, par->ExtCRTDispAddr);
+  VGAwGR(0x0F, par->ExtCRTOffset);
+  temp = VGArGR(0x10);
+  temp &= 0x0F; /* Save bits 3:0 */
+  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
+  VGAwGR(0x10, temp);
+
+  VGAwGR(0x11, par->SysIfaceCntl2);
+  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
+  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
+
+  temp = VGArGR(0x20);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xFC; /* Save bits 7:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xFC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      temp &= 0xDC; /* Save bits 7:6,4:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xDC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x98; /* Save bits 7,4:3 */
+      temp |= (par->PanelDispCntlReg1 & ~0x98);
+      break;
+    }
+  VGAwGR(0x20, temp);
+
+  temp = VGArGR(0x25);
+  temp &= 0x38; /* Save bits 5:3 */
+  temp |= (par->PanelDispCntlReg2 & ~0x38);
+  VGAwGR(0x25, temp);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      temp = VGArGR(0x30);
+      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
+      temp |= (par->PanelDispCntlReg3 & ~0xEF);
+      VGAwGR(0x30, temp);
+    }
+
+  VGAwGR(0x28, par->PanelVertCenterReg1);
+  VGAwGR(0x29, par->PanelVertCenterReg2);
+  VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      VGAwGR(0x32, par->PanelVertCenterReg4);
+      VGAwGR(0x33, par->PanelHorizCenterReg1);
+      VGAwGR(0x34, par->PanelHorizCenterReg2);
+      VGAwGR(0x35, par->PanelHorizCenterReg3);
+    }
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
+    VGAwGR(0x36, par->PanelHorizCenterReg4);
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwGR(0x36, par->PanelHorizCenterReg4);
+      VGAwGR(0x37, par->PanelVertCenterReg5);
+      VGAwGR(0x38, par->PanelHorizCenterReg5);
+
+      clock_hi = 1;
+    }
+
+  /* Program VCLK3 if needed. */
+  if (par->ProgramVCLK
+      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+	  || (VGArGR(0x9F) !=  par->VCLK3Denominator)
+	  || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+			   != (par->VCLK3NumeratorHigh & ~0x0F)))))
+    {
+      VGAwGR(0x9B, par->VCLK3NumeratorLow);
+      if (clock_hi)
+	{
+	  temp = VGArGR(0x8F);
+	  temp &= 0x0F; /* Save bits 3:0 */
+	  temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+	  VGAwGR(0x8F, temp);
+	}
+      VGAwGR(0x9F, par->VCLK3Denominator);
+    }
+
+  if (par->biosMode)
+    VGAwCR(0x23, par->biosMode);
+    
+  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
+
+  /* Program vertical extension register */
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwCR(0x70, par->VerticalExt);
+    }
+
+
+  vgaHWProtect (0);		/* Turn on screen */
+
+  /* Calling this also locks offset registers required in update_start */
+  neoLock();
+}
+
+static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
+{
+  int oldExtCRTDispAddr;
+  int Base; 
+
+  DBG("neofb_update_start");
+
+  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+  Base *= (var->bits_per_pixel + 7) / 8;
+
+  neoUnlock();
+
+  /*
+   * These are the generic starting address registers.
+   */
+  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+  VGAwCR(0x0D, (Base & 0x00FF));
+
+  /*
+   * Make sure we don't clobber some other bits that might already
+   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+   * be needed.
+   */
+  oldExtCRTDispAddr = VGArGR(0x0E);
+  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+  neoLock();
+}
+
+/*
+ * Set the Colormap
+ */
+static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
+  struct fb_cmap *dcmap = &disp->cmap;
+  int err = 0;
+
+  /* no colormap allocated? */
+  if (!dcmap->len)
+    {
+      int size;
+
+      if (fb->var.bits_per_pixel == 8)
+	size = NR_PALETTE;
+      else
+	size = 32;
+
+      err = fb_alloc_cmap (dcmap, size, 0);
+    }
+
+  /*
+   * we should be able to remove this test once fbcon has been
+   * "improved" --rmk
+   */
+  if (!err && con == info->currcon)
+    {
+      err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
+      dcmap = &fb->cmap;
+    }
+
+  if (!err)
+    fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
+
+  return err;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 0xe517  /* 14.31818 in 20.12 fixed point */
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
+{
+  int n, d, f;
+  int n_best = 0, d_best = 0, f_best = 0;
+  long f_best_diff = (0x7ffff << 12); /* 20.12 */
+  long f_target = (freq << 12) / 1000; /* 20.12 */
+
+  for (f = 0; f <= MAX_F; f++)
+    for (n = 0; n <= MAX_N; n++)
+      for (d = 0; d <= MAX_D; d++)
+	{
+          long f_out;  /* 20.12 */
+          long f_diff; /* 20.12 */
+
+	  f_out = ((((n+1) << 12)  /  ((d+1)*(1<<f))) >> 12)  *  REF_FREQ;
+	  f_diff = abs(f_out-f_target);
+	  if (f_diff < f_best_diff)
+	    {
+	      f_best_diff = f_diff;
+	      n_best = n;
+	      d_best = d;
+	      f_best = f;
+	    }
+	}
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      /* NOT_DONE:  We are trying the full range of the 2200 clock.
+	 We should be able to try n up to 2047 */
+      par->VCLK3NumeratorLow  = n_best;
+      par->VCLK3NumeratorHigh = (f_best << 7);
+    }
+  else
+    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
+
+  par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+  printk ("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
+	  f_target >> 12,
+	  par->VCLK3NumeratorLow,
+	  par->VCLK3NumeratorHigh,
+	  par->VCLK3Denominator,
+	  f_best_diff >> 12);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
+
+static int vgaHWInit (const struct fb_var_screeninfo *var,
+		      const struct neofb_info        *info,
+		      struct neofb_par               *par,
+		      struct xtimings                *timings)
+{
+  par->MiscOutReg = 0x23;
+
+  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+    par->MiscOutReg |= 0x40;
+
+  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+    par->MiscOutReg |= 0x80;
+    
+  /*
+   * Time Sequencer
+   */
+  par->Sequencer[0] = 0x00;
+  par->Sequencer[1] = 0x01;
+  par->Sequencer[2] = 0x0F;
+  par->Sequencer[3] = 0x00;                             /* Font select */
+  par->Sequencer[4] = 0x0E;                             /* Misc */
+
+  /*
+   * CRTC Controller
+   */
+  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
+  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+  par->CRTC[4]  = (timings->HSyncStart >> 3);
+  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+    | (((timings->HSyncEnd >> 3)) & 0x1F);
+  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
+  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
+    | (((timings->VDisplay - 1) & 0x100) >> 7)
+    | ((timings->VSyncStart & 0x100) >> 6)
+    | (((timings->VDisplay - 1) & 0x100) >> 5)
+    | 0x10
+    | (((timings->VTotal - 2) & 0x200)   >> 4)
+    | (((timings->VDisplay - 1) & 0x200) >> 3)
+    | ((timings->VSyncStart & 0x200) >> 2);
+  par->CRTC[8]  = 0x00;
+  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+  if (timings->dblscan)
+    par->CRTC[9] |= 0x80;
+
+  par->CRTC[10] = 0x00;
+  par->CRTC[11] = 0x00;
+  par->CRTC[12] = 0x00;
+  par->CRTC[13] = 0x00;
+  par->CRTC[14] = 0x00;
+  par->CRTC[15] = 0x00;
+  par->CRTC[16] = timings->VSyncStart & 0xFF;
+  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+  par->CRTC[19] = var->xres_virtual >> 4;
+  par->CRTC[20] = 0x00;
+  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
+  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+  par->CRTC[23] = 0xC3;
+  par->CRTC[24] = 0xFF;
+
+  /*
+   * are these unnecessary?
+   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   */
+
+  /*
+   * Graphics Display Controller
+   */
+  par->Graphics[0] = 0x00;
+  par->Graphics[1] = 0x00;
+  par->Graphics[2] = 0x00;
+  par->Graphics[3] = 0x00;
+  par->Graphics[4] = 0x00;
+  par->Graphics[5] = 0x40;
+  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
+  par->Graphics[7] = 0x0F;
+  par->Graphics[8] = 0xFF;
+  
+
+  par->Attribute[0]  = 0x00; /* standard colormap translation */
+  par->Attribute[1]  = 0x01;
+  par->Attribute[2]  = 0x02;
+  par->Attribute[3]  = 0x03;
+  par->Attribute[4]  = 0x04;
+  par->Attribute[5]  = 0x05;
+  par->Attribute[6]  = 0x06;
+  par->Attribute[7]  = 0x07;
+  par->Attribute[8]  = 0x08;
+  par->Attribute[9]  = 0x09;
+  par->Attribute[10] = 0x0A;
+  par->Attribute[11] = 0x0B;
+  par->Attribute[12] = 0x0C;
+  par->Attribute[13] = 0x0D;
+  par->Attribute[14] = 0x0E;
+  par->Attribute[15] = 0x0F;
+  par->Attribute[16] = 0x41;
+  par->Attribute[17] = 0xFF;
+  par->Attribute[18] = 0x0F;
+  par->Attribute[19] = 0x00;
+  par->Attribute[20] = 0x00;
+
+  return 0;
+}
+
+static int neofb_decode_var (struct fb_var_screeninfo        *var,
+                             const struct neofb_info         *info,
+                             struct neofb_par                *par)
+{
+  struct xtimings timings;
+  int lcd_stretch;
+  int hoffset, voffset;
+  int memlen, vramlen;
+  int mode_ok = 0;
+  unsigned int pixclock = var->pixclock;
+
+  DBG("neofb_decode_var");
+
+  if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+  timings.pixclock = 1000000000 / pixclock;
+  if (timings.pixclock < 1) timings.pixclock = 1;
+  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+  timings.HDisplay = var->xres;
+  timings.HSyncStart = timings.HDisplay + var->right_margin;
+  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+  timings.HTotal = timings.HSyncEnd + var->left_margin;
+  timings.VDisplay = var->yres;
+  timings.VSyncStart = timings.VDisplay + var->lower_margin;
+  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+  timings.VTotal = timings.VSyncEnd + var->upper_margin;
+  timings.sync = var->sync;
+
+  if (timings.pixclock > info->maxClock)
+    return -EINVAL;
+
+  /* Is the mode larger than the LCD panel? */
+  if ((var->xres > info->NeoPanelWidth) ||
+      (var->yres > info->NeoPanelHeight))
+    {
+      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+	      var->xres,
+	      var->yres,
+	      info->NeoPanelWidth,
+	      info->NeoPanelHeight);
+      return -EINVAL;
+    }
+
+  /* Is the mode one of the acceptable sizes? */
+  switch (var->xres)
+    {
+    case 1280:
+      if (var->yres == 1024)
+	mode_ok = 1;
+      break;
+    case 1024:
+      if (var->yres == 768)
+	mode_ok = 1;
+      break;
+    case  800:
+      if (var->yres == 600)
+	mode_ok = 1;
+      break;
+    case  640:
+      if (var->yres == 480)
+	mode_ok = 1;
+      break;
+    }
+
+  if (!mode_ok)
+    {
+      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
+	      var->xres, var->yres);
+      return -EINVAL;
+    }
+
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32:
+      break;
+# endif
+#endif
+
+    default:
+      return -EINVAL;
+    }
+
+  par->depth = var->bits_per_pixel;
+
+  vramlen = info->video.len;
+  if (vramlen > 4*1024*1024)
+    vramlen = 4*1024*1024;
+
+  if (var->yres_virtual < var->yres)
+    var->yres_virtual = var->yres;
+  if (var->xres_virtual < var->xres)
+    var->xres_virtual = var->xres;
+
+  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+  if (memlen > vramlen)
+    {
+      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+    }
+
+  /* we must round yres/xres down, we already rounded y/xres_virtual up
+     if it was possible. We should return -EINVAL, but I disagree */
+  if (var->yres_virtual < var->yres)
+    var->yres = var->yres_virtual;
+  if (var->xres_virtual < var->xres)
+    var->xres = var->xres_virtual;
+  if (var->xoffset + var->xres > var->xres_virtual)
+    var->xoffset = var->xres_virtual - var->xres;
+  if (var->yoffset + var->yres > var->yres_virtual)
+    var->yoffset = var->yres_virtual - var->yres;
+
+
+  /*
+   * This will allocate the datastructure and initialize all of the
+   * generic VGA registers.
+   */
+
+  if (vgaHWInit (var, info, par, &timings))
+    return -EINVAL;
+
+  /*
+   * The default value assigned by vgaHW.c is 0x41, but this does
+   * not work for NeoMagic.
+   */
+  par->Attribute[16] = 0x01;
+
+  switch (var->bits_per_pixel)
+    {
+    case  8:
+      par->CRTC[0x13]   = var->xres_virtual >> 3;
+      par->ExtCRTOffset = var->xres_virtual >> 11;
+      par->ExtColorModeSelect = 0x11;
+      break;
+    case 16:
+      par->CRTC[0x13]   = var->xres_virtual >> 2;
+      par->ExtCRTOffset = var->xres_virtual >> 10;
+      par->ExtColorModeSelect = 0x13;
+      break;
+    case 24:
+      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
+      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
+      par->ExtColorModeSelect = 0x14;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32: /* FIXME: guessed values */
+      par->CRTC[0x13]   = var->xres_virtual >> 1;
+      par->ExtCRTOffset = var->xres_virtual >> 9;
+      par->ExtColorModeSelect = 0x15;
+      break;
+#endif
+    default:
+      break;
+    }
+	
+  par->ExtCRTDispAddr = 0x10;
+
+  /* Vertical Extension */
+  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
+    | (((timings.VDisplay -1) & 0x400) >> 9 )
+    | (((timings.VSyncStart) & 0x400) >> 8 )
+    | (((timings.VSyncStart) & 0x400) >> 7 );
+
+  /* Fast write bursts on unless disabled. */
+  if (info->pci_burst)
+    par->SysIfaceCntl1 = 0x30; 
+  else
+    par->SysIfaceCntl1 = 0x00; 
+
+  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
+
+  /* Enable any user specified display devices. */
+  par->PanelDispCntlReg1 = 0x00;
+  if (info->internal_display)
+    par->PanelDispCntlReg1 |= 0x02;
+  if (info->external_display)
+    par->PanelDispCntlReg1 |= 0x01;
+
+  /* If the user did not specify any display devices, then... */
+  if (par->PanelDispCntlReg1 == 0x00) {
+    /* Default to internal (i.e., LCD) only. */
+    par->PanelDispCntlReg1 |= 0x02;
+  }
+
+  /* If we are using a fixed mode, then tell the chip we are. */
+  switch (var->xres)
+    {
+    case 1280:
+      par->PanelDispCntlReg1 |= 0x60;
+      break;
+    case 1024:
+      par->PanelDispCntlReg1 |= 0x40;
+      break;
+    case 800:
+      par->PanelDispCntlReg1 |= 0x20;
+      break;
+    case 640:
+    default:
+      break;
+    }
+  
+  /* Setup shadow register locking. */
+  switch (par->PanelDispCntlReg1 & 0x03)
+    {
+    case 0x01: /* External CRT only mode: */
+      par->GeneralLockReg = 0x00;
+      /* We need to program the VCLK for external display only mode. */
+      par->ProgramVCLK = 1;
+      break;
+    case 0x02: /* Internal LCD only mode: */
+    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
+      par->GeneralLockReg = 0x01;
+      /* Don't program the VCLK when using the LCD. */
+      par->ProgramVCLK = 0;
+      break;
+    }
+
+  /*
+   * If the screen is to be stretched, turn on stretching for the
+   * various modes.
+   *
+   * OPTION_LCD_STRETCH means stretching should be turned off!
+   */
+  par->PanelDispCntlReg2 = 0x00;
+  par->PanelDispCntlReg3 = 0x00;
+
+  if (info->lcd_stretch &&
+      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
+      (var->xres != info->NeoPanelWidth))
+    {
+      switch (var->xres)
+	{
+	case  320: /* Needs testing.  KEM -- 24 May 98 */
+	case  400: /* Needs testing.  KEM -- 24 May 98 */
+	case  640:
+	case  800:
+	case 1024:
+	  lcd_stretch = 1;
+	  par->PanelDispCntlReg2 |= 0xC6;
+	  break;
+	default:
+	  lcd_stretch = 0;
+	  /* No stretching in these modes. */
+	}
+    }
+  else
+    lcd_stretch = 0;
+
+  /*
+   * If the screen is to be centerd, turn on the centering for the
+   * various modes.
+   */
+  par->PanelVertCenterReg1  = 0x00;
+  par->PanelVertCenterReg2  = 0x00;
+  par->PanelVertCenterReg3  = 0x00;
+  par->PanelVertCenterReg4  = 0x00;
+  par->PanelVertCenterReg5  = 0x00;
+  par->PanelHorizCenterReg1 = 0x00;
+  par->PanelHorizCenterReg2 = 0x00;
+  par->PanelHorizCenterReg3 = 0x00;
+  par->PanelHorizCenterReg4 = 0x00;
+  par->PanelHorizCenterReg5 = 0x00;
+
+
+  if (par->PanelDispCntlReg1 & 0x02)
+    {
+      if (var->xres == info->NeoPanelWidth)
+	{
+	  /*
+	   * No centering required when the requested display width
+	   * equals the panel width.
+	   */
+	}
+      else
+	{
+	  par->PanelDispCntlReg2 |= 0x01;
+	  par->PanelDispCntlReg3 |= 0x10;
+
+	  /* Calculate the horizontal and vertical offsets. */
+	  if (!lcd_stretch)
+	    {
+	      hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
+	      voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
+	    }
+	  else
+	    {
+	      /* Stretched modes cannot be centered. */
+	      hoffset = 0;
+	      voffset = 0;
+	    }
+
+	  switch (var->xres)
+	    {
+	    case  320: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg3 = hoffset;
+	      par->PanelVertCenterReg2  = voffset;
+	      break;
+	    case  400: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg4 = hoffset;
+	      par->PanelVertCenterReg1  = voffset;
+	      break;
+	    case  640:
+	      par->PanelHorizCenterReg1 = hoffset;
+	      par->PanelVertCenterReg3  = voffset;
+	      break;
+	    case  800:
+	      par->PanelHorizCenterReg2 = hoffset;
+	      par->PanelVertCenterReg4  = voffset;
+	      break;
+	    case 1024:
+	      par->PanelHorizCenterReg5 = hoffset;
+	      par->PanelVertCenterReg5  = voffset;
+	      break;
+	    case 1280:
+	    default:
+	      /* No centering in these modes. */
+	      break;
+	    }
+	}
+    }
+
+  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
+    
+  /*
+   * Calculate the VCLK that most closely matches the requested dot
+   * clock.
+   */
+  neoCalcVCLK (info, par, timings.pixclock);
+
+  /* Since we program the clocks ourselves, always use VCLK3. */
+  par->MiscOutReg |= 0x0C;
+
+  return 0;
+}
+
+static int neofb_set_var (struct fb_var_screeninfo *var, int con,
+                          struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *display;
+  struct neofb_par par;
+  int err, chgvar = 0;
+
+  DBG("neofb_set_var");
+
+  err = neofb_decode_var (var, info, &par);
+  if (err)
+    return err;
+
+  if (var->activate & FB_ACTIVATE_TEST)
+    return 0;
+
+  if (con < 0)
+    {
+      display = fb->disp;
+      chgvar = 0;
+    }
+  else
+    {
+      display = fb_display + con;
+
+      if (fb->var.xres != var->xres)
+	chgvar = 1;
+      if (fb->var.yres != var->yres)
+	chgvar = 1;
+      if (fb->var.xres_virtual != var->xres_virtual)
+	chgvar = 1;
+      if (fb->var.yres_virtual != var->yres_virtual)
+	chgvar = 1;
+      if (fb->var.bits_per_pixel != var->bits_per_pixel)
+	chgvar = 1;
+    }
+
+  if (!info->neo2200)
+    var->accel_flags &= ~FB_ACCELF_TEXT;
+
+  var->red.msb_right	= 0;
+  var->green.msb_right	= 0;
+  var->blue.msb_right	= 0;
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:	/* PSEUDOCOLOUR, 256 */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 0;
+      var->red.length      = 8;
+      var->green.offset	   = 0;
+      var->green.length	   = 8;
+      var->blue.offset	   = 0;
+      var->blue.length	   = 8;
+      
+      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+      info->dispsw         = &fbcon_cfb8;
+      display->dispsw_data = NULL;
+      display->next_line   = var->xres_virtual;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16: /* DIRECTCOLOUR, 64k */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 11;
+      var->red.length      = 5;
+      var->green.offset    = 5;
+      var->green.length    = 6;
+      var->blue.offset     = 0;
+      var->blue.length     = 5;
+
+      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
+      info->dispsw         = &fbcon_cfb16;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 2;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb24;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 3;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 24;
+      var->transp.length   = 8;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb32;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 4;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+# endif
+#endif
+
+    default:
+      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
+      info->dispsw      = &fbcon_dummy;
+      var->accel_flags &= ~FB_ACCELF_TEXT;
+      break;
+    }
+
+  if (var->accel_flags & FB_ACCELF_TEXT)
+    display->dispsw = &fbcon_neo2200_accel;
+  else
+    display->dispsw = info->dispsw;
+
+  fb->fix.line_length = display->next_line;
+
+  display->screen_base    = fb->screen_base;
+  display->line_length    = fb->fix.line_length;
+  display->visual         = fb->fix.visual;
+  display->type	          = fb->fix.type;
+  display->type_aux       = fb->fix.type_aux;
+  display->ypanstep       = fb->fix.ypanstep;
+  display->ywrapstep      = fb->fix.ywrapstep;
+  display->can_soft_blank = 1;
+  display->inverse        = 0;
+
+  fb->var = *var;
+  fb->var.activate &= ~FB_ACTIVATE_ALL;
+
+  /*
+   * Update the old var.  The fbcon drivers still use this.
+   * Once they are using cfb->fb.var, this can be dropped.
+   *					--rmk
+   */
+  display->var = fb->var;
+
+  /*
+   * If we are setting all the virtual consoles, also set the
+   * defaults used to create new consoles.
+   */
+  if (var->activate & FB_ACTIVATE_ALL)
+    fb->disp->var = fb->var;
+
+  if (chgvar && fb && fb->changevar)
+    fb->changevar (con);
+
+  if (con == info->currcon)
+    {
+      if (chgvar || con < 0)
+        neofb_set_par (info, &par);
+
+      neofb_update_start (info, var);
+      fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
+
+      if (var->accel_flags & FB_ACCELF_TEXT)
+	neo2200_accel_init (info, var);
+    }
+
+  return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
+			      struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  u_int y_bottom;
+
+  y_bottom = var->yoffset;
+
+  if (!(var->vmode & FB_VMODE_YWRAP))
+    y_bottom += var->yres;
+
+  if (var->xoffset > (var->xres_virtual - var->xres))
+    return -EINVAL;
+  if (y_bottom > fb->var.yres_virtual)
+    return -EINVAL;
+
+  neofb_update_start (info, var);
+
+  fb->var.xoffset = var->xoffset;
+  fb->var.yoffset = var->yoffset;
+
+  if (var->vmode & FB_VMODE_YWRAP)
+    fb->var.vmode |= FB_VMODE_YWRAP;
+  else
+    fb->var.vmode &= ~FB_VMODE_YWRAP;
+
+  return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+static int neofb_updatevar (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  neofb_update_start (info, &fb_display[con].var);
+
+  return 0;
+}
+
+static int neofb_switch (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *disp;
+  struct fb_cmap *cmap;
+
+  if (info->currcon >= 0)
+    {
+      disp = fb_display + info->currcon;
+
+      /*
+       * Save the old colormap and video mode.
+       */
+      disp->var = fb->var;
+      if (disp->cmap.len)
+	fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
+    }
+
+  info->currcon = con;
+  disp = fb_display + con;
+
+  /*
+   * Install the new colormap and change the video mode.  By default,
+   * fbcon sets all the colormaps and video modes to the default
+   * values at bootup.
+   *
+   * Really, we want to set the colourmap size depending on the
+   * depth of the new video mode.  For now, we leave it at its
+   * default 256 entry.
+   */
+  if (disp->cmap.len)
+    cmap = &disp->cmap;
+  else
+    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+  fb_copy_cmap(cmap, &fb->cmap, 0);
+
+  disp->var.activate = FB_ACTIVATE_NOW;
+  neofb_set_var(&disp->var, con, fb);
+
+  return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static void neofb_blank (int blank, struct fb_info *fb)
+{
+  //  struct neofb_info *info = (struct neofb_info *)fb;
+
+  /*
+   *  Blank the screen if blank_mode != 0, else unblank. If
+   *  blank == NULL then the caller blanks by setting the CLUT
+   *  (Color Look Up Table) to all black. Return 0 if blanking
+   *  succeeded, != 0 if un-/blanking failed due to e.g. a
+   *  video mode which doesn't support it. Implements VESA
+   *  suspend and powerdown modes on hardware that supports
+   *  disabling hsync/vsync:
+   *    blank_mode == 2: suspend vsync
+   *    blank_mode == 3: suspend hsync
+   *    blank_mode == 4: powerdown
+   *
+   *  wms...Enable VESA DMPS compatible powerdown mode
+   *  run "setterm -powersave powerdown" to take advantage
+   */
+     
+  switch (blank)
+    {
+    case 4:	/* powerdown - both sync lines down */
+      break;	
+    case 3:	/* hsync off */
+      break;	
+    case 2:	/* vsync off */
+      break;	
+    case 1:	/* just software blanking of screen */
+      break;
+    default: /* case 0, or anything else: unblank */
+      break;
+    }
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
+{
+  fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
+  return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+  *fix = fb->fix;
+  return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+  *var = fb->var;
+  return 0;
+}
+
+static struct fb_ops neofb_ops = {
+  owner:          THIS_MODULE,
+  fb_set_var:     neofb_set_var,
+  fb_set_cmap:    neofb_set_cmap,
+  fb_pan_display: neofb_pan_display,
+  fb_get_fix:     gen_get_fix,
+  fb_get_var:     gen_get_var,
+  fb_get_cmap:    gen_get_cmap,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		640,
+	yres:		480,
+	xres_virtual:   640,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	39722,
+	left_margin:	48,
+	right_margin:	16,
+	upper_margin:	33,
+	lower_margin:	10,
+	hsync_len:	96,
+	vsync_len:	2,
+	sync:		0,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		800,
+	yres:		600,
+	xres_virtual:   800,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	25000,
+	left_margin:	88,
+	right_margin:	40,
+	upper_margin:	23,
+	lower_margin:	1,
+	hsync_len:	128,
+	vsync_len:	4,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1024,
+	yres:		768,
+	xres_virtual:   1024,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	15385,
+	left_margin:	160,
+	right_margin:	24,
+	upper_margin:	29,
+	lower_margin:	3,
+	hsync_len:	136,
+	vsync_len:	6,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+#ifdef NOT_DONE
+static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1280,
+	yres:		1024,
+	xres_virtual:   1280,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	9260,
+	left_margin:	248,
+	right_margin:	48,
+	upper_margin:	38,
+	lower_margin:	1,
+	hsync_len:	112,
+	vsync_len:	3,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+#endif
+
+static struct fb_var_screeninfo *neofb_var = NULL;
+
+
+static int __devinit neo_map_mmio (struct neofb_info *info)
+{
+  DBG("neo_map_mmio");
+
+  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
+  info->mmio.len   = MMIO_SIZE;
+
+  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
+    {
+      printk ("neofb: memory mapped IO in use\n");
+      return -EBUSY;
+    }
+
+  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
+  if (!info->mmio.vbase)
+    {
+      printk ("neofb: unable to map memory mapped IO\n");
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+
+  info->fb.fix.mmio_start = info->mmio.pbase;
+  info->fb.fix.mmio_len   = info->mmio.len;
+
+  return 0;
+}
+
+static void __devinit neo_unmap_mmio (struct neofb_info *info)
+{
+  DBG("neo_unmap_mmio");
+
+  if (info->mmio.vbase)
+    {
+      iounmap (info->mmio.vbase);
+      info->mmio.vbase = NULL;
+
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+    }
+}
+
+static int __devinit neo_map_video (struct neofb_info *info, int video_len)
+{
+  DBG("neo_map_video");
+
+  info->video.pbase = pci_resource_start (info->pcidev, 0);
+  info->video.len   = video_len;
+
+  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
+    {
+      printk ("neofb: frame buffer in use\n");
+      return -EBUSY;
+    }
+
+  info->video.vbase = ioremap (info->video.pbase, info->video.len);
+  if (!info->video.vbase)
+    {
+      printk ("neofb: unable to map screen memory\n");
+      release_mem_region (info->video.pbase, info->video.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+
+  info->fb.fix.smem_start = info->video.pbase;
+  info->fb.fix.smem_len   = info->video.len;
+  info->fb.screen_base    = info->video.vbase;
+
+#ifdef CONFIG_MTRR
+  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+#endif
+
+  /* Clear framebuffer, it's all white in memory after boot */
+  memset (info->video.vbase, 0, info->video.len);
+
+  return 0;
+}
+
+static void __devinit neo_unmap_video (struct neofb_info *info)
+{
+  DBG("neo_unmap_video");
+
+  if (info->video.vbase)
+    {
+#ifdef CONFIG_MTRR
+      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
+#endif
+
+      iounmap (info->video.vbase);
+      info->video.vbase = NULL;
+      info->fb.screen_base = NULL;
+
+      release_mem_region (info->video.pbase, info->video.len);
+    }
+}
+
+static int __devinit neo_init_hw (struct neofb_info *info)
+{
+  int videoRam = 896;
+  int maxClock = 65000;
+  int CursorMem = 1024;
+  int CursorOff = 0x100;
+  int linearSize = 1024;
+  int maxWidth = 1024;
+  int maxHeight = 1024;
+  unsigned char type, display;
+  int w;
+    
+  DBG("neo_init_hw");
+
+  neoUnlock();
+
+#if 0
+  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
+  for (w=0; w<0x85; w++)
+    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
+  for (w=0; w<0xC7; w++)
+    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
+#endif
+
+  /* Determine the panel type */
+  VGAwGR(0x09,0x26);
+  type = VGArGR(0x21);
+  display = VGArGR(0x20);
+    
+  /* Determine panel width -- used in NeoValidMode. */
+  w = VGArGR(0x20);
+  VGAwGR(0x09,0x00);
+  switch ((w & 0x18) >> 3)
+    {
+    case 0x00:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    case 0x01:
+      info->NeoPanelWidth  = 800;
+      info->NeoPanelHeight = 600;
+      neofb_var = &neofb_var800x600x8;
+      break;
+    case 0x02:
+      info->NeoPanelWidth  = 1024;
+      info->NeoPanelHeight = 768;
+      neofb_var = &neofb_var1024x768x8;
+      break;
+    case 0x03:
+      /* 1280x1024 panel support needs to be added */
+#ifdef NOT_DONE
+      info->NeoPanelWidth  = 1280;
+      info->NeoPanelHeight = 1024;
+      neofb_var = &neofb_var1280x1024x8;
+      break;
+#else
+      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+      return -1;
+#endif
+    default:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    }
+
+  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
+	  info->NeoPanelWidth,
+	  info->NeoPanelHeight,
+	  (type & 0x02) ? "color" : "monochrome",
+	  (type & 0x10) ? "TFT" : "dual scan");
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      videoRam   = 896;
+      maxClock   = 65000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 1024;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      videoRam   = 2048;
+      maxClock   = 90000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      videoRam   = 2560;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      videoRam   = 3008;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      videoRam   = 4096;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      videoRam   = 6144;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 8192;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    }
+
+  info->maxClock = maxClock;
+
+  return videoRam * 1024;
+}
+
+
+static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
+							const struct pci_device_id *id)
+{
+  struct neofb_info *info;
+
+  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
+		  sizeof(u32) * 16, GFP_KERNEL);
+
+  if (!info)
+    return NULL;
+
+  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
+
+  info->currcon = -1;
+  info->pcidev  = dev;
+  info->accel   = id->driver_data;
+
+  info->pci_burst   = !nopciburst;
+  info->lcd_stretch = !nostretch;
+
+  if (!internal && !external)
+    {
+      info->internal_display = 1;
+      info->external_display = 0;
+    }
+  else
+    {
+      info->internal_display = internal;
+      info->external_display = external;
+    }
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      sprintf (info->fb.fix.id, "MagicGraph 128");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+      sprintf (info->fb.fix.id, "MagicGraph 128V");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      sprintf (info->fb.fix.id, "MagicGraph 128XD");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
+      break;
+    }
+
+  info->fb.fix.type	   = FB_TYPE_PACKED_PIXELS;
+  info->fb.fix.type_aux	   = 0;
+  info->fb.fix.xpanstep	   = 0;
+  info->fb.fix.ypanstep	   = 4;
+  info->fb.fix.ywrapstep   = 0;
+  info->fb.fix.accel       = id->driver_data;
+
+  info->fb.var.nonstd      = 0;
+  info->fb.var.activate    = FB_ACTIVATE_NOW;
+  info->fb.var.height      = -1;
+  info->fb.var.width       = -1;
+  info->fb.var.accel_flags = 0;
+
+  strcpy (info->fb.modename, info->fb.fix.id);
+
+  info->fb.fbops          = &neofb_ops;
+  info->fb.changevar      = NULL;
+  info->fb.switch_con     = neofb_switch;
+  info->fb.updatevar      = neofb_updatevar;
+  info->fb.blank          = neofb_blank;
+  info->fb.flags          = FBINFO_FLAG_DEFAULT;
+  info->fb.disp           = (struct display *)(info + 1);
+  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
+
+  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
+
+  return info;
+}
+
+static void __devinit neo_free_fb_info (struct neofb_info *info)
+{
+  if (info)
+    {
+      /*
+       * Free the colourmap
+       */
+      fb_alloc_cmap (&info->fb.cmap, 0, 0);
+
+      kfree (info);
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+{
+  struct neofb_info *info;
+  u_int h_sync, v_sync;
+  int err;
+  int video_len;
+
+  DBG("neofb_probe");
+
+  err = pci_enable_device (dev);
+  if (err)
+    return err;
+
+  err = -ENOMEM;
+  info = neo_alloc_fb_info (dev, id);
+  if (!info)
+    goto failed;
+
+  err = neo_map_mmio (info);
+  if (err)
+    goto failed;
+
+  video_len = neo_init_hw (info);
+  if (video_len < 0)
+    {
+      err = video_len;
+      goto failed;
+    }
+
+  err = neo_map_video (info, video_len);
+  if (err)
+    goto failed;
+
+  neofb_set_var (neofb_var, -1, &info->fb);
+
+  /*
+   * Calculate the hsync and vsync frequencies.  Note that
+   * we split the 1e12 constant up so that we can preserve
+   * the precision and fit the results into 32-bit registers.
+   *  (1953125000 * 512 = 1e12)
+   */
+  h_sync = 1953125000 / info->fb.var.pixclock;
+  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
+			   info->fb.var.right_margin + info->fb.var.hsync_len);
+  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
+		     info->fb.var.lower_margin + info->fb.var.vsync_len);
+
+  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	 info->fb.fix.smem_len >> 10,
+	 info->fb.var.xres, info->fb.var.yres,
+	 h_sync / 1000, h_sync % 1000, v_sync);
+
+
+  err = register_framebuffer (&info->fb);
+  if (err < 0)
+    goto failed;
+
+  printk (KERN_INFO "fb%d: %s frame buffer device\n",
+	  GET_FB_IDX(info->fb.node), info->fb.modename);
+
+  /*
+   * Our driver data
+   */
+  dev->driver_data = info;
+
+  return 0;
+
+failed:
+  neo_unmap_video (info);
+  neo_unmap_mmio (info);
+  neo_free_fb_info (info);
+
+  return err;
+}
+
+static void __devexit neofb_remove (struct pci_dev *dev)
+{
+  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+
+  DBG("neofb_remove");
+
+  if (info)
+    {
+      /*
+       * If unregister_framebuffer fails, then
+       * we will be leaving hooks that could cause
+       * oopsen laying around.
+       */
+      if (unregister_framebuffer (&info->fb))
+	printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
+
+      neo_unmap_video (info);
+      neo_unmap_mmio (info);
+      neo_free_fb_info (info);
+
+      /*
+       * Ensure that the driver data is no longer
+       * valid.
+       */
+      dev->driver_data = NULL;
+    }
+}
+
+static struct pci_device_id neofb_devices[] __devinitdata = {
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+  {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+  name:      "neofb",
+  id_table:  neofb_devices,
+  probe:     neofb_probe,
+  remove:    neofb_remove
+};
+
+/* **************************** init-time only **************************** */
+
+static void __init neo_init (void)
+{
+  DBG("neo_init");
+  pci_register_driver (&neofb_driver);
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit neo_done (void)
+{
+  DBG("neo_done");
+  pci_unregister_driver (&neofb_driver);
+}
+
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init neofb_setup (char *options)
+{
+  char *this_opt;
+
+  DBG("neofb_setup");
+
+  if (!options || !*options)
+    return 0;
+
+  for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
+    {
+      if (!*this_opt) continue;
+
+      if (!strncmp(this_opt, "disabled", 8))
+	disabled = 1;
+      if (!strncmp(this_opt, "internal", 8))
+	internal = 1;
+      if (!strncmp(this_opt, "external", 8))
+	external = 1;
+      if (!strncmp(this_opt, "nostretch", 9))
+	nostretch = 1;
+      if (!strncmp(this_opt, "nopciburst", 10))
+	nopciburst = 1;
+    }
+
+  return 0;
+}
+
+static int __init initialized = 0;
+
+int __init neofb_init(void)
+{
+  DBG("neofb_init");
+
+  if (disabled)
+    return -ENXIO;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      neo_init();
+    }
+
+  /* never return failure, user can hotplug card later... */
+  return 0;
+}
+
+#else
+
+/* *************************** init module code **************************** */
+
+int __init init_module(void)
+{
+  DBG("init_module");
+
+  if (disabled)
+    return -ENXIO;
+
+  neo_init();
+
+  /* never return failure; user can hotplug card later... */
+  return 0;
+}
+
+#endif	/* MODULE */
+
+module_exit(neo_done);
diff -urN linux-2.4.19-pre2/drivers/video/neofb.h linux-2.4.19-pre3/drivers/video/neofb.h
--- linux-2.4.19-pre2/drivers/video/neofb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/drivers/video/neofb.h	Mon Mar 11 14:13:30 2002
@@ -0,0 +1,294 @@
+/*
+ * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+
+#ifdef NEOFB_DEBUG
+# define DBG(x)		printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+  unsigned int pixclock;
+  unsigned int HDisplay;
+  unsigned int HSyncStart;
+  unsigned int HSyncEnd;
+  unsigned int HTotal;
+  unsigned int VDisplay;
+  unsigned int VSyncStart;
+  unsigned int VSyncEnd;
+  unsigned int VTotal;
+  unsigned int sync;
+  int	       dblscan;
+  int	       interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+  __u32 bltStat;
+  __u32 bltCntl;
+  __u32 xpColor;
+  __u32 fgColor;
+  __u32 bgColor;
+  __u32 pitch;
+  __u32 clipLT;
+  __u32 clipRB;
+  __u32 srcBitOffset;
+  __u32 srcStart;
+  __u32 reserved0;
+  __u32 dstStart;
+  __u32 xyExt;
+
+  __u32 reserved1[19];
+
+  __u32 pageCntl;
+  __u32 pageBase;
+  __u32 postBase;
+  __u32 postPtr;
+  __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE	256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+
+  int depth;
+
+  unsigned char MiscOutReg;     /* Misc */
+  unsigned char CRTC[25];       /* Crtc Controller */
+  unsigned char Sequencer[5];   /* Video Sequencer */
+  unsigned char Graphics[9];    /* Video Graphics */
+  unsigned char Attribute[21];  /* Video Atribute */
+
+  unsigned char GeneralLockReg;
+  unsigned char ExtCRTDispAddr;
+  unsigned char ExtCRTOffset;
+  unsigned char SysIfaceCntl1;
+  unsigned char SysIfaceCntl2;
+  unsigned char ExtColorModeSelect;
+  unsigned char biosMode;
+
+  unsigned char PanelDispCntlReg1;
+  unsigned char PanelDispCntlReg2;
+  unsigned char PanelDispCntlReg3;
+  unsigned char PanelVertCenterReg1;
+  unsigned char PanelVertCenterReg2;
+  unsigned char PanelVertCenterReg3;
+  unsigned char PanelVertCenterReg4;
+  unsigned char PanelVertCenterReg5;
+  unsigned char PanelHorizCenterReg1;
+  unsigned char PanelHorizCenterReg2;
+  unsigned char PanelHorizCenterReg3;
+  unsigned char PanelHorizCenterReg4;
+  unsigned char PanelHorizCenterReg5;
+
+  int           ProgramVCLK;
+  unsigned char VCLK3NumeratorLow;
+  unsigned char VCLK3NumeratorHigh;
+  unsigned char VCLK3Denominator;
+  unsigned char VerticalExt;
+};
+
+struct neofb_info {
+
+  struct fb_info  fb;
+  struct display_switch	*dispsw;
+
+  struct pci_dev *pcidev;
+
+  int   currcon;
+
+  int   accel;
+  char *name;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+#ifdef CONFIG_MTRR
+    int    mtrr;
+#endif
+  } video;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+  } mmio;
+
+  Neo2200 *neo2200;
+
+  /* Panels size */
+  int NeoPanelWidth;
+  int NeoPanelHeight;
+
+  int maxClock;
+
+  int pci_burst;
+  int lcd_stretch;
+  int internal_display;
+  int external_display;
+
+  struct {
+    u16 red, green, blue, transp;
+  } palette[NR_PALETTE];
+};
+
+
+typedef struct {
+    int x_res;
+    int y_res;
+    int mode;
+} biosMode;
+
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+  outb (index, 0x3d4);
+  outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+  outb (index, 0x3ce);
+  outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+  outb (index, 0x3c4);
+  outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x00, 0x3c0);
+  paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x20, 0x3c0);
+  paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+  u8 tmp;
+
+  if (paletteEnabled)
+    index &= ~0x20;
+  else
+    index |= 0x20;
+
+  tmp = inb (0x3da);
+  outb (index, 0x3c0);
+  outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+  outb (value, 0x3c2);
+}
+
+
+#define NEO_BS0_BLT_BUSY        0x00000001
+#define NEO_BS0_FIFO_AVAIL      0x00000002
+#define NEO_BS0_FIFO_PEND       0x00000004
+
+#define NEO_BC0_DST_Y_DEC       0x00000001
+#define NEO_BC0_X_DEC           0x00000002
+#define NEO_BC0_SRC_TRANS       0x00000004
+#define NEO_BC0_SRC_IS_FG       0x00000008
+#define NEO_BC0_SRC_Y_DEC       0x00000010
+#define NEO_BC0_FILL_PAT        0x00000020
+#define NEO_BC0_SRC_MONO        0x00000040
+#define NEO_BC0_SYS_TO_VID      0x00000080
+
+#define NEO_BC1_DEPTH8          0x00000100
+#define NEO_BC1_DEPTH16         0x00000200
+#define NEO_BC1_X_320           0x00000400
+#define NEO_BC1_X_640           0x00000800
+#define NEO_BC1_X_800           0x00000c00
+#define NEO_BC1_X_1024          0x00001000
+#define NEO_BC1_X_1152          0x00001400
+#define NEO_BC1_X_1280          0x00001800
+#define NEO_BC1_X_1600          0x00001c00
+#define NEO_BC1_DST_TRANS       0x00002000
+#define NEO_BC1_MSTR_BLT        0x00004000
+#define NEO_BC1_FILTER_Z        0x00008000
+
+#define NEO_BC2_WR_TR_DST       0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR     0x01000000
+#define NEO_BC3_DST_XY_ADDR     0x02000000
+#define NEO_BC3_CLIP_ON         0x04000000
+#define NEO_BC3_FIFO_EN         0x08000000
+#define NEO_BC3_BLT_ON_ADDR     0x10000000
+#define NEO_BC3_SKIP_MAPPING    0x80000000
+
+#define NEO_MODE1_DEPTH8        0x0100
+#define NEO_MODE1_DEPTH16       0x0200
+#define NEO_MODE1_DEPTH24       0x0300
+#define NEO_MODE1_X_320         0x0400
+#define NEO_MODE1_X_640         0x0800
+#define NEO_MODE1_X_800         0x0c00
+#define NEO_MODE1_X_1024        0x1000
+#define NEO_MODE1_X_1152        0x1400
+#define NEO_MODE1_X_1280        0x1800
+#define NEO_MODE1_X_1600        0x1c00
+#define NEO_MODE1_BLT_ON_ADDR   0x2000
diff -urN linux-2.4.19-pre2/drivers/video/newport_con.c linux-2.4.19-pre3/drivers/video/newport_con.c
--- linux-2.4.19-pre2/drivers/video/newport_con.c	Mon Mar 11 14:13:22 2002
+++ linux-2.4.19-pre3/drivers/video/newport_con.c	Mon Oct 15 13:47:24 2001
@@ -719,6 +719,8 @@
 };
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	if (!newport_startup())
diff -urN linux-2.4.19-pre2/drivers/video/sgivwfb.c linux-2.4.19-pre3/drivers/video/sgivwfb.c
--- linux-2.4.19-pre2/drivers/video/sgivwfb.c	Wed Nov 14 14:52:20 2001
+++ linux-2.4.19-pre3/drivers/video/sgivwfb.c	Mon Mar 11 14:13:30 2002
@@ -846,7 +846,6 @@
     return -EINVAL;
   offset += sgivwfb_mem_phys;
   pgprot_val(vma->vm_page_prot) = pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
-  vma->vm_flags |= VM_IO;
   if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot))
     return -EAGAIN;
   vma->vm_file = file;
diff -urN linux-2.4.19-pre2/drivers/video/sstfb.c linux-2.4.19-pre3/drivers/video/sstfb.c
--- linux-2.4.19-pre2/drivers/video/sstfb.c	Wed Nov 14 14:52:20 2001
+++ linux-2.4.19-pre3/drivers/video/sstfb.c	Mon Mar 11 14:13:30 2002
@@ -5,12 +5,16 @@
  *
  *     Created 15 Jan 2000 by Ghozlane Toumi
  *
+ *     NOTE: I have been unable to reach Ghozlane through the eMail-address
+ *     given above for more than 3 months, same with another address of him
+ *     which I found on the web. - Urs
+ *
  * Contributions (and many thanks) :
  *
  * 03/2001 James Simmons   <jsimmons@linux-fbdev.org>
  * 04/2001 Paul Mundt      <lethal@chaoticdreams.org>
- * 05/2001 Urs Ganse       <urs.ganse@t-online.de>
- *     (initial work on voodoo2 port)
+ * 05/2001 Urs Ganse       <ursg@uni.de>
+ *     (initial work on voodoo2 port, added interlace support)
  *
  *
  * $Id: sstfb.c,v 1.26.4.1 2001/08/29 01:30:37 ghoz Exp $
@@ -59,6 +63,8 @@
 -TODO: change struct sst_info fb_info from static to array/dynamic
   TTT comments is for code i've put there for debuging the "weird peinguin 
   	syndrome", it should disapear soon
+-FIXME: Some uninitialized variable causes sporadic crashes when setting a video
+       mode for the first time.
 
  *
  */
@@ -208,7 +214,7 @@
 
 /********/
 
-/* Interface to ze oueurld  */
+/* Interface to the world  */
 int sstfb_init(void);
 int sstfb_setup(char *options);
 
@@ -599,9 +605,8 @@
 		         var->xres, var->yres);
 		return -EINVAL;
 	}
-	if ((var->vmode & FB_VMODE_MASK) !=  FB_VMODE_NONINTERLACED) {
-		eprintk("Interlace non supported %#x\n",
-			(var->vmode & FB_VMODE_MASK));
+	if((var->vmode & FB_VMODE_MASK) && !sst_info->is_voodoo2 ){
+		eprintk ("Interlace modes not supported on Voodoo 1 hardware.\n");
 		return -EINVAL;
 	}
 
@@ -615,7 +620,17 @@
 	par->vSyncOn    = var->vsync_len;
 	par->vSyncOff   = var->yres + var->lower_margin + var->upper_margin;
 	par->vBackPorch = var->upper_margin;
-
+	
+	par->flags      = 0;
+	if (var->vmode & FB_VMODE_INTERLACED) {
+//		printk(KERN_DEBUG "sstfb: This is an interlace mode.\n");
+		par->flags|=FB_VMODE_INTERLACED;
+	}
+	if(var->vmode & FB_VMODE_DOUBLE) {
+//		printk(KERN_DEBUG "sstfb: This is a doublescan mode.\n");
+		par->flags|=FB_VMODE_DOUBLE;
+	}
+		
 	switch (var->bits_per_pixel) {
 	case 0 ... 16 :
 		par->bpp = 16;
@@ -685,7 +700,7 @@
 	var->lower_margin   = par->vSyncOff - par->yDim - par->vBackPorch;
 	var->hsync_len      = par->hSyncOn;
 	var->vsync_len      = par->vSyncOn;
-	var->vmode          = FB_VMODE_NONINTERLACED;
+	var->vmode          = par->flags;
 
 	/*
 	 * correct the color bit fields
@@ -1375,6 +1390,17 @@
 	sst_write(HSYNC,         (par->hSyncOff-1) << 16 | (par->hSyncOn-1));
 	sst_write(VSYNC,             par->vSyncOff << 16 | par->vSyncOn);
 
+	/* Interlace or Doublescan */
+	if(par->flags & FB_VMODE_INTERLACED)
+		sst_set_bits(FBIINIT5,1>>26);
+	else
+		sst_unset_bits(FBIINIT5,1>>26);
+	
+	if(par->flags & FB_VMODE_DOUBLE)
+		sst_set_bits(FBIINIT5,1>>20);
+	else
+		sst_unset_bits(FBIINIT5,1>>20);
+	
 	fbiinit2=sst_read(FBIINIT2);
 	fbiinit3=sst_read(FBIINIT3);
 
diff -urN linux-2.4.19-pre2/drivers/video/sstfb.h linux-2.4.19-pre3/drivers/video/sstfb.h
--- linux-2.4.19-pre2/drivers/video/sstfb.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre3/drivers/video/sstfb.h	Mon Mar 11 14:13:30 2002
@@ -317,6 +317,7 @@
 	unsigned int vSyncOn;
 	unsigned int vSyncOff;
 	unsigned int vBackPorch;
+	unsigned int flags;	/* Doublescan, Interlace etc. */
 	unsigned int freq;	/* freq in picoseconds */
 	unsigned int tiles_in_X; /* num of tiles in X res */
 };
diff -urN linux-2.4.19-pre2/fs/bad_inode.c linux-2.4.19-pre3/fs/bad_inode.c
--- linux-2.4.19-pre2/fs/bad_inode.c	Wed Apr 12 09:47:28 2000
+++ linux-2.4.19-pre3/fs/bad_inode.c	Mon Mar 11 14:13:30 2002
@@ -17,9 +17,7 @@
  */
 static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
 {
-	dput(nd->dentry);
-	nd->dentry = dget(dent);
-	return 0;
+	return vfs_follow_link(nd, ERR_PTR(-EIO));
 }
 
 static int return_EIO(void)
diff -urN linux-2.4.19-pre2/fs/pipe.c linux-2.4.19-pre3/fs/pipe.c
--- linux-2.4.19-pre2/fs/pipe.c	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/fs/pipe.c	Mon Mar 11 14:13:30 2002
@@ -248,12 +248,6 @@
 	return -EPIPE;
 }
 
-static loff_t
-pipe_lseek(struct file *file, loff_t offset, int orig)
-{
-	return -ESPIPE;
-}
-
 static ssize_t
 bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos)
 {
@@ -383,7 +377,7 @@
  * are also used in linux/fs/fifo.c to do operations on FIFOs.
  */
 struct file_operations read_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		bad_pipe_w,
 	poll:		fifo_poll,
@@ -393,7 +387,7 @@
 };
 
 struct file_operations write_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		bad_pipe_r,
 	write:		pipe_write,
 	poll:		fifo_poll,
@@ -403,7 +397,7 @@
 };
 
 struct file_operations rdwr_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		pipe_write,
 	poll:		fifo_poll,
@@ -413,7 +407,7 @@
 };
 
 struct file_operations read_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		bad_pipe_w,
 	poll:		pipe_poll,
@@ -423,7 +417,7 @@
 };
 
 struct file_operations write_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		bad_pipe_r,
 	write:		pipe_write,
 	poll:		pipe_poll,
@@ -433,7 +427,7 @@
 };
 
 struct file_operations rdwr_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		pipe_write,
 	poll:		pipe_poll,
diff -urN linux-2.4.19-pre2/fs/reiserfs/bitmap.c linux-2.4.19-pre3/fs/reiserfs/bitmap.c
--- linux-2.4.19-pre2/fs/reiserfs/bitmap.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/bitmap.c	Mon Mar 11 14:13:30 2002
@@ -139,10 +139,8 @@
 /* preallocated blocks don't need to be run through journal_mark_freed */
 void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th, 
                           unsigned long block) {
-    struct super_block * s = th->t_super;
-
-    RFALSE(!s, "vs-4060: trying to free block on nonexistent device");
-    RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block");
+    RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
+    RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
     _reiserfs_free_block(th, block) ;
 }
 
diff -urN linux-2.4.19-pre2/fs/reiserfs/dir.c linux-2.4.19-pre3/fs/reiserfs/dir.c
--- linux-2.4.19-pre2/fs/reiserfs/dir.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/dir.c	Mon Mar 11 14:13:30 2002
@@ -20,6 +20,7 @@
     read:	generic_read_dir,
     readdir:	reiserfs_readdir,
     fsync:	reiserfs_dir_fsync,
+    ioctl:	reiserfs_ioctl,
 };
 
 int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
@@ -76,7 +77,7 @@
 		
 	/* we must have found item, that is item of this directory, */
 	RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
-		"vs-9000: found item %h does not match to dir we readdir %k",
+		"vs-9000: found item %h does not match to dir we readdir %K",
 		ih, &pos_key);
 	RFALSE( item_num > B_NR_ITEMS (bh) - 1,
 		"vs-9005 item_num == %d, item amount == %d", 
@@ -115,13 +116,13 @@
 		if (d_reclen <= 32) {
 		  local_buf = small_buf ;
 		} else {
-		    local_buf = kmalloc(d_reclen, GFP_NOFS) ;
+		    local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
 		    if (!local_buf) {
 			pathrelse (&path_to_entry);
 			return -ENOMEM ;
 		    }
 		    if (item_moved (&tmp_ih, &path_to_entry)) {
-			kfree(local_buf) ;
+			reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
 			goto research;
 		    }
 		}
@@ -133,12 +134,12 @@
 		if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, 
 		             DT_UNKNOWN) < 0) {
 		    if (local_buf != small_buf) {
-			kfree(local_buf) ;
+			reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
 		    }
 		    goto end;
 		}
 		if (local_buf != small_buf) {
-		    kfree(local_buf) ;
+		    reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
 		}
 
 		// next entry should be looked for with such offset
@@ -180,6 +181,7 @@
     filp->f_pos = next_pos;
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
+    UPDATE_ATIME(inode) ;
     return 0;
 }
 
diff -urN linux-2.4.19-pre2/fs/reiserfs/fix_node.c linux-2.4.19-pre3/fs/reiserfs/fix_node.c
--- linux-2.4.19-pre2/fs/reiserfs/fix_node.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/fix_node.c	Mon Mar 11 14:13:30 2002
@@ -1979,7 +1979,7 @@
     return CARRY_ON;
 }
 
-
+#ifdef CONFIG_REISERFS_CHECK
 void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s)
 {
     void * vp;
@@ -2007,6 +2007,7 @@
 	reiserfs_warning ("vs-8302: reiserfs_kfree: allocated memory %d\n", s->u.reiserfs_sb.s_kmallocs);
 
 }
+#endif
 
 
 static int get_virtual_node_size (struct super_block * sb, struct buffer_head * bh)
@@ -2356,7 +2357,6 @@
     for ( n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++ ) { 
 	if ( (n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON ) {
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = check_balance (n_op_mode, p_s_tb, n_h, n_item_num,
@@ -2365,7 +2365,6 @@
 		/* No balancing for higher levels needed. */
 		if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
 		    goto repeat;
-		    return n_ret_value;
 		}
 		if ( n_h != MAX_HEIGHT - 1 )  
 		    p_s_tb->insert_size[n_h + 1] = 0;
@@ -2373,17 +2372,14 @@
 		break;
 	    }
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON ) {
-	    goto repeat;
-	    return n_ret_value; /* No disk space, or schedule occurred and
+	    goto repeat;        /* No disk space, or schedule occurred and
 				   analysis may be invalid and needs to be redone. */
 	}
     
diff -urN linux-2.4.19-pre2/fs/reiserfs/inode.c linux-2.4.19-pre3/fs/reiserfs/inode.c
--- linux-2.4.19-pre2/fs/reiserfs/inode.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/inode.c	Mon Mar 11 14:13:30 2002
@@ -445,6 +445,24 @@
     return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE) ;
 }
 
+static int reiserfs_get_block_direct_io (struct inode * inode, long block,
+			struct buffer_head * bh_result, int create) {
+    int ret ;
+
+    ret = reiserfs_get_block(inode, block, bh_result, create) ;
+
+    /* don't allow direct io onto tail pages */
+    if (ret == 0 && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
+	/* make sure future calls to the direct io funcs for this offset
+	** in the file fail by unmapping the buffer
+	*/
+	reiserfs_unmap_buffer(bh_result);
+        ret = -EINVAL ;
+    }
+    return ret ;
+}
+
+
 /*
 ** helper function for when reiserfs_get_block is called for a hole
 ** but the file tail is still in a direct item
@@ -748,14 +766,24 @@
 
 		retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
 		if (retval) {
-		    printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ;
-		    if (allocated_block_nr)
+		    if ( retval != -ENOSPC )
+			printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ;
+		    if (allocated_block_nr) {
+			/* the bitmap, the super, and the stat data == 3 */
+			journal_begin(&th, inode->i_sb, 3) ;
 			reiserfs_free_block (&th, allocated_block_nr);
+			transaction_started = 1 ;
+		    }
 		    goto failure ;
 		}
 		goto research ;
 	    }
 	    retval = direct2indirect (&th, inode, &path, unbh, tail_offset);
+	    if (retval) {
+		reiserfs_unmap_buffer(unbh);
+		reiserfs_free_block (&th, allocated_block_nr);
+		goto failure;
+	    }
 	    /* it is important the mark_buffer_uptodate is done after
 	    ** the direct2indirect.  The buffer might contain valid
 	    ** data newer than the data on disk (read by readpage, changed,
@@ -765,10 +793,7 @@
 	    ** the disk
 	    */
 	    mark_buffer_uptodate (unbh, 1);
-	    if (retval) {
-		reiserfs_free_block (&th, allocated_block_nr);
-		goto failure;
-	    }
+
 	    /* we've converted the tail, so we must 
 	    ** flush unbh before the transaction commits
 	    */
@@ -914,7 +939,7 @@
 	inode->i_blocks = sd_v1_blocks(sd);
 	inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
 	blocks = (inode->i_size + 511) >> 9;
-	blocks = _ROUND_UP (blocks, inode->i_blksize >> 9);
+	blocks = _ROUND_UP (blocks, inode->i_sb->s_blocksize >> 9);
 	if (inode->i_blocks > blocks) {
 	    // there was a bug in <=3.5.23 when i_blocks could take negative
 	    // values. Starting from 3.5.17 this value could even be stored in
@@ -926,6 +951,9 @@
 
         rdev = sd_v1_rdev(sd);
 	inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
+	/* nopack is initially zero for v1 objects. For v2 objects,
+	   nopack is initialised from sd_attrs */
+	inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
     } else {
 	// new stat data found, but object may have old items
 	// (directories and symlinks)
@@ -952,10 +980,12 @@
             set_inode_item_key_version (inode, KEY_FORMAT_3_6);
 
         set_inode_sd_version (inode, STAT_DATA_V2);
+	/* read persistent inode attributes from sd and initalise
+	   generic inode flags from them */
+	inode -> u.reiserfs_i.i_attrs = sd_v2_attrs( sd );
+	sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );
     }
 
-    /* nopack = 0, by default */
-    inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -979,6 +1009,7 @@
 static void inode2sd (void * sd, struct inode * inode)
 {
     struct stat_data * sd_v2 = (struct stat_data *)sd;
+    __u16 flags;
 
     set_sd_v2_mode(sd_v2, inode->i_mode );
     set_sd_v2_nlink(sd_v2, inode->i_nlink );
@@ -989,13 +1020,13 @@
     set_sd_v2_atime(sd_v2, inode->i_atime );
     set_sd_v2_ctime(sd_v2, inode->i_ctime );
     set_sd_v2_blocks(sd_v2, inode->i_blocks );
-    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
         set_sd_v2_rdev(sd_v2, inode->i_rdev );
-}
     else
-    {
         set_sd_v2_generation(sd_v2, inode->i_generation);
-    }
+    flags = inode -> u.reiserfs_i.i_attrs;
+    i_attrs_to_sd_attrs( inode, &flags );
+    set_sd_v2_attrs( sd_v2, flags );
 }
 
 
@@ -1493,7 +1524,9 @@
     }
 
     sb = dir->i_sb;
-    inode->i_flags = 0;//inode->i_sb->s_flags;
+    inode -> u.reiserfs_i.i_attrs = 
+	    dir -> u.reiserfs_i.i_attrs & REISERFS_INHERIT_MASK;
+    sd_attrs_to_i_attrs( inode -> u.reiserfs_i.i_attrs, inode );
 
     /* item head of new item */
     ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
@@ -1552,6 +1585,10 @@
     } else
 	inode->i_gid = current->fsgid;
 
+    /* symlink cannot be immutable or append only, right? */
+    if( S_ISLNK( inode -> i_mode ) )
+	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
+
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
     inode->i_blocks = (inode->i_size + 511) >> 9;
@@ -1898,14 +1935,21 @@
 static inline void submit_bh_for_writepage(struct buffer_head **bhp, int nr) {
     struct buffer_head *bh ;
     int i;
+
+    /* lock them all first so the end_io handler doesn't unlock the page
+    ** too early
+    */
     for(i = 0 ; i < nr ; i++) {
         bh = bhp[i] ;
 	lock_buffer(bh) ;
 	set_buffer_async_io(bh) ;
+    }
+    for(i = 0 ; i < nr ; i++) {
 	/* submit_bh doesn't care if the buffer is dirty, but nobody
 	** later on in the call chain will be cleaning it.  So, we
 	** clean the buffer here, it still gets written either way.
 	*/
+        bh = bhp[i] ;
 	clear_bit(BH_Dirty, &bh->b_state) ;
 	set_bit(BH_Uptodate, &bh->b_state) ;
 	submit_bh(WRITE, bh) ;
@@ -2073,11 +2117,64 @@
     return ret ;
 }
 
+void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
+{
+	if( reiserfs_attrs( inode -> i_sb ) ) {
+		if( sd_attrs & REISERFS_SYNC_FL )
+			inode -> i_flags |= S_SYNC;
+		else
+			inode -> i_flags &= ~S_SYNC;
+		if( sd_attrs & REISERFS_IMMUTABLE_FL )
+			inode -> i_flags |= S_IMMUTABLE;
+		else
+			inode -> i_flags &= ~S_IMMUTABLE;
+		if( sd_attrs & REISERFS_NOATIME_FL )
+			inode -> i_flags |= S_NOATIME;
+		else
+			inode -> i_flags &= ~S_NOATIME;
+		if( sd_attrs & REISERFS_NOTAIL_FL )
+			inode->u.reiserfs_i.i_flags |= i_nopack_mask;
+		else
+			inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;
+	}
+}
+
+void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
+{
+	if( reiserfs_attrs( inode -> i_sb ) ) {
+		if( inode -> i_flags & S_IMMUTABLE )
+			*sd_attrs |= REISERFS_IMMUTABLE_FL;
+		else
+			*sd_attrs &= ~REISERFS_IMMUTABLE_FL;
+		if( inode -> i_flags & S_SYNC )
+			*sd_attrs |= REISERFS_SYNC_FL;
+		else
+			*sd_attrs &= ~REISERFS_SYNC_FL;
+		if( inode -> i_flags & S_NOATIME )
+			*sd_attrs |= REISERFS_NOATIME_FL;
+		else
+			*sd_attrs &= ~REISERFS_NOATIME_FL;
+		if( inode->u.reiserfs_i.i_flags & i_nopack_mask )
+			*sd_attrs |= REISERFS_NOTAIL_FL;
+		else
+			*sd_attrs &= ~REISERFS_NOTAIL_FL;
+	}
+}
+
+static int reiserfs_direct_io(int rw, struct inode *inode, 
+                              struct kiobuf *iobuf, unsigned long blocknr,
+			      int blocksize) 
+{
+    return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize,
+                             reiserfs_get_block_direct_io) ;
+}
+
 struct address_space_operations reiserfs_address_space_operations = {
     writepage: reiserfs_writepage,
     readpage: reiserfs_readpage, 
     sync_page: block_sync_page,
     prepare_write: reiserfs_prepare_write,
     commit_write: reiserfs_commit_write,
-    bmap: reiserfs_aop_bmap
+    bmap: reiserfs_aop_bmap,
+    direct_IO: reiserfs_direct_io,
 } ;
diff -urN linux-2.4.19-pre2/fs/reiserfs/ioctl.c linux-2.4.19-pre3/fs/reiserfs/ioctl.c
--- linux-2.4.19-pre2/fs/reiserfs/ioctl.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/ioctl.c	Mon Mar 11 14:13:30 2002
@@ -14,17 +14,70 @@
 ** supported commands:
 **  1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
 **                           and prevent packing file (argument arg has to be non-zero)
-**  2) That's all for a while ...
+**  2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
+**  3) That's all for a while ...
 */
 int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		unsigned long arg)
 {
+	unsigned int flags;
+
 	switch (cmd) {
 	    case REISERFS_IOC_UNPACK:
+		if( S_ISREG( inode -> i_mode ) ) {
 		if (arg)
 		    return reiserfs_unpack (inode, filp);
+			else
+				return 0;
+		} else
+			return -ENOTTY;
+	/* following two cases are taken from fs/ext2/ioctl.c by Remy
+	   Card (card@masi.ibp.fr) */
+	case REISERFS_IOC_GETFLAGS:
+		flags = inode -> u.reiserfs_i.i_attrs;
+		i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
+		return put_user(flags, (int *) arg);
+	case REISERFS_IOC_SETFLAGS: {
+		if (IS_RDONLY(inode))
+			return -EROFS;
+
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EPERM;
+
+		if (get_user(flags, (int *) arg))
+			return -EFAULT;
+
+		if ( ( flags & REISERFS_IMMUTABLE_FL ) && 
+		     !capable( CAP_LINUX_IMMUTABLE ) )
+			return -EPERM;
 			
-	    default:
+		if( ( flags & REISERFS_NOTAIL_FL ) &&
+		    S_ISREG( inode -> i_mode ) ) {
+				int result;
+
+				result = reiserfs_unpack( inode, filp );
+				if( result )
+					return result;
+		}
+		sd_attrs_to_i_attrs( flags, inode );
+		inode -> u.reiserfs_i.i_attrs = flags;
+		inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(inode);
+		return 0;
+	}
+	case REISERFS_IOC_GETVERSION:
+		return put_user(inode->i_generation, (int *) arg);
+	case REISERFS_IOC_SETVERSION:
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EPERM;
+		if (IS_RDONLY(inode))
+			return -EROFS;
+		if (get_user(inode->i_generation, (int *) arg))
+			return -EFAULT;	
+		inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(inode);
+		return 0;
+	default:
 		return -ENOTTY;
 	}
 }
@@ -43,7 +96,8 @@
     unsigned long blocksize = inode->i_sb->s_blocksize ;
     	
     if (inode->i_size == 0) {
-        return -EINVAL ;
+        inode->u.reiserfs_i.i_flags |= i_nopack_mask;
+        return 0 ;
     }
     /* ioctl already done */
     if (inode->u.reiserfs_i.i_flags & i_nopack_mask) {
diff -urN linux-2.4.19-pre2/fs/reiserfs/item_ops.c linux-2.4.19-pre3/fs/reiserfs/item_ops.c
--- linux-2.4.19-pre2/fs/reiserfs/item_ops.c	Fri Oct 12 14:19:28 2001
+++ linux-2.4.19-pre3/fs/reiserfs/item_ops.c	Mon Mar 11 14:13:30 2002
@@ -685,17 +685,110 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
+// Error catching functions to catch errors caused by incorrect item types.
+//
+static int errcatch_bytes_number (struct item_head * ih, int block_size)
+{
+    reiserfs_warning ("green-16001: Invalid item type observed, run fsck ASAP\n");
+    return 0;
+}
+
+static void errcatch_decrement_key (struct cpu_key * key)
+{
+    reiserfs_warning ("green-16002: Invalid item type observed, run fsck ASAP\n");
+}
+
+
+static int errcatch_is_left_mergeable (struct key * key, unsigned long bsize)
+{
+    reiserfs_warning ("green-16003: Invalid item type observed, run fsck ASAP\n");
+    return 0;
+}
+
+
+static void errcatch_print_item (struct item_head * ih, char * item)
+{
+    reiserfs_warning ("green-16004: Invalid item type observed, run fsck ASAP\n");
+}
+
+
+static void errcatch_check_item (struct item_head * ih, char * item)
+{
+    reiserfs_warning ("green-16005: Invalid item type observed, run fsck ASAP\n");
+}
+
+static int errcatch_create_vi (struct virtual_node * vn,
+			       struct virtual_item * vi, 
+			       int is_affected, 
+			       int insert_size)
+{
+    reiserfs_warning ("green-16006: Invalid item type observed, run fsck ASAP\n");
+    return 0;	// We might return -1 here as well, but it won't help as create_virtual_node() from where
+		// this operation is called from is of return type void.
+}
+
+static int errcatch_check_left (struct virtual_item * vi, int free,
+				int start_skip, int end_skip)
+{
+    reiserfs_warning ("green-16007: Invalid item type observed, run fsck ASAP\n");
+    return -1;
+}
+
+
+static int errcatch_check_right (struct virtual_item * vi, int free)
+{
+    reiserfs_warning ("green-16008: Invalid item type observed, run fsck ASAP\n");
+    return -1;
+}
+
+static int errcatch_part_size (struct virtual_item * vi, int first, int count)
+{
+    reiserfs_warning ("green-16009: Invalid item type observed, run fsck ASAP\n");
+    return 0;
+}
+
+static int errcatch_unit_num (struct virtual_item * vi)
+{
+    reiserfs_warning ("green-16010: Invalid item type observed, run fsck ASAP\n");
+    return 0;
+}
+
+static void errcatch_print_vi (struct virtual_item * vi)
+{
+    reiserfs_warning ("green-16011: Invalid item type observed, run fsck ASAP\n");
+}
+
+struct item_operations errcatch_ops = {
+    errcatch_bytes_number,
+    errcatch_decrement_key,
+    errcatch_is_left_mergeable,
+    errcatch_print_item,
+    errcatch_check_item,
+
+    errcatch_create_vi,
+    errcatch_check_left,
+    errcatch_check_right,
+    errcatch_part_size,
+    errcatch_unit_num,
+    errcatch_print_vi
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////
 //
 //
 #if ! (TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3)
   do not compile
 #endif
 
-struct item_operations * item_ops [4] = {
+struct item_operations * item_ops [TYPE_ANY + 1] = {
   &stat_data_ops,
   &indirect_ops,
   &direct_ops,
-  &direntry_ops
+  &direntry_ops,
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+  &errcatch_ops		/* This is to catch errors with invalid type (15th entry for TYPE_ANY) */
 };
 
 
diff -urN linux-2.4.19-pre2/fs/reiserfs/journal.c linux-2.4.19-pre3/fs/reiserfs/journal.c
--- linux-2.4.19-pre2/fs/reiserfs/journal.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/journal.c	Mon Mar 11 14:13:30 2002
@@ -71,7 +71,9 @@
 static DECLARE_WAIT_QUEUE_HEAD(reiserfs_commit_thread_done) ;
 DECLARE_TASK_QUEUE(reiserfs_commit_thread_tq) ;
 
-#define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit structs at 4k */
+#define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit
+				     structs at 4k */
+#define BUFNR 64 /*read ahead */
 
 /* cnode stat bits.  Move these into reiserfs_fs.h */
 
@@ -117,13 +119,13 @@
   struct reiserfs_bitmap_node *bn ;
   static int id = 0 ;
 
-  bn = kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS) ;
+  bn = reiserfs_kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS, p_s_sb) ;
   if (!bn) {
     return NULL ;
   }
-  bn->data = kmalloc(p_s_sb->s_blocksize, GFP_NOFS) ;
+  bn->data = reiserfs_kmalloc(p_s_sb->s_blocksize, GFP_NOFS, p_s_sb) ;
   if (!bn->data) {
-    kfree(bn) ;
+    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
     return NULL ;
   }
   bn->id = id++ ;
@@ -159,8 +161,8 @@
                                     struct reiserfs_bitmap_node *bn) {
   SB_JOURNAL(p_s_sb)->j_used_bitmap_nodes-- ;
   if (SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) {
-    kfree(bn->data) ;
-    kfree(bn) ;
+    reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;
+    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
   } else {
     list_add(&bn->list, &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
     SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes++ ;
@@ -228,8 +230,8 @@
   while(next != &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) {
     bn = list_entry(next, struct reiserfs_bitmap_node, list) ;
     list_del(next) ;
-    kfree(bn->data) ;
-    kfree(bn) ;
+    reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;
+    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
     next = SB_JOURNAL(p_s_sb)->j_bitmap_nodes.next ;
     SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes-- ;
   }
@@ -1500,13 +1502,13 @@
   }
   trans_id = le32_to_cpu(desc->j_trans_id) ;
   /* now we know we've got a good transaction, and it was inside the valid time ranges */
-  log_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ;
-  real_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ;
+  log_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ;
+  real_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ;
   if (!log_blocks  || !real_blocks) {
     brelse(c_bh) ;
     brelse(d_bh) ;
-    kfree(log_blocks) ;
-    kfree(real_blocks) ;
+    reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
+    reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
     reiserfs_warning("journal-1169: kmalloc failed, unable to mount FS\n") ;
     return -1 ;
   }
@@ -1525,8 +1527,8 @@
       brelse_array(real_blocks, i) ;
       brelse(c_bh) ;
       brelse(d_bh) ;
-      kfree(log_blocks) ;
-      kfree(real_blocks) ;
+      reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
+      reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
       return -1 ;
     }
   }
@@ -1540,8 +1542,8 @@
       brelse_array(real_blocks, le32_to_cpu(desc->j_len)) ;
       brelse(c_bh) ;
       brelse(d_bh) ;
-      kfree(log_blocks) ;
-      kfree(real_blocks) ;
+      reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
+      reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
       return -1 ;
     }
     memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ;
@@ -1560,8 +1562,8 @@
       brelse_array(real_blocks + i, le32_to_cpu(desc->j_len) - i) ;
       brelse(c_bh) ;
       brelse(d_bh) ;
-      kfree(log_blocks) ;
-      kfree(real_blocks) ;
+      reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
+      reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
       return -1 ;
     }
     brelse(real_blocks[i]) ;
@@ -1577,8 +1579,8 @@
   SB_JOURNAL(p_s_sb)->j_trans_id = trans_id + 1;
   brelse(c_bh) ;
   brelse(d_bh) ;
-  kfree(log_blocks) ;
-  kfree(real_blocks) ;
+  reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
+  reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
   return 0 ;
 }
 
@@ -1591,6 +1593,41 @@
 **
 ** On exit, it sets things up so the first transaction will work correctly.
 */
+struct buffer_head * reiserfs_breada (kdev_t dev, int block, int bufsize,
+			    unsigned int max_block)
+{
+	struct buffer_head * bhlist[BUFNR];
+	unsigned int blocks = BUFNR;
+	struct buffer_head * bh;
+	int i, j;
+	
+	bh = getblk (dev, block, bufsize);
+	if (buffer_uptodate (bh))
+		return (bh);   
+		
+	if (block + BUFNR > max_block) {
+		blocks = max_block - block;
+	}
+	bhlist[0] = bh;
+	j = 1;
+	for (i = 1; i < blocks; i++) {
+		bh = getblk (dev, block + i, bufsize);
+		if (buffer_uptodate (bh)) {
+			brelse (bh);
+			break;
+		}
+		else bhlist[j++] = bh;
+	}
+	ll_rw_block (READ, j, bhlist);
+	for(i = 1; i < j; i++) 
+		brelse (bhlist[i]);
+	bh = bhlist[0];
+	wait_on_buffer (bh);
+	if (buffer_uptodate (bh))
+		return bh;
+	brelse (bh);
+	return NULL;
+}
 static int journal_read(struct super_block *p_s_sb) {
   struct reiserfs_journal_desc *desc ;
   unsigned long last_flush_trans_id = 0 ;
@@ -1660,7 +1697,8 @@
   ** all the valid transactions, and pick out the oldest.
   */
   while(continue_replay && cur_dblock < (reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT)) {
-    d_bh = sb_bread(p_s_sb, cur_dblock) ;
+    d_bh = reiserfs_breada(p_s_sb->s_dev, cur_dblock, p_s_sb->s_blocksize,
+			   reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ;
     if (ret == 1) {
       desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
@@ -1777,7 +1815,7 @@
       atomic_read(&(jl->j_commit_left)) == 0) {
     kupdate_one_transaction(ct->p_s_sb, jl) ;
   }
-  kfree(ct->self) ;
+  reiserfs_kfree(ct->self, sizeof(struct reiserfs_journal_commit_task), ct->p_s_sb) ;
 }
 
 static void setup_commit_task_arg(struct reiserfs_journal_commit_task *ct,
@@ -1801,7 +1839,7 @@
   /* using GFP_NOFS, GFP_KERNEL could try to flush inodes, which will try
   ** to start/join a transaction, which will deadlock
   */
-  ct = kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS) ;
+  ct = reiserfs_kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS, p_s_sb) ;
   if (ct) {
     setup_commit_task_arg(ct, p_s_sb, jindex) ;
     queue_task(&(ct->task), &reiserfs_commit_thread_tq);
diff -urN linux-2.4.19-pre2/fs/reiserfs/namei.c linux-2.4.19-pre3/fs/reiserfs/namei.c
--- linux-2.4.19-pre2/fs/reiserfs/namei.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/namei.c	Mon Mar 11 14:13:30 2002
@@ -340,7 +340,7 @@
 static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry)
 {
     int retval;
-    struct inode * inode = 0;
+    struct inode * inode = NULL;
     struct reiserfs_dir_entry de;
     INITIALIZE_PATH (path_to_entry);
 
@@ -358,6 +358,9 @@
 	    return ERR_PTR(-EACCES);
         }
     }
+    if ( retval == IO_ERROR ) {
+	return ERR_PTR(-EIO);
+    }
 
     d_add(dentry, inode);
     return NULL;
@@ -443,6 +446,10 @@
 	    reiserfs_kfree (buffer, buflen, dir->i_sb);
 	pathrelse (&path);
 
+	if ( retval == IO_ERROR ) {
+	    return -EIO;
+	}
+
         if (retval != NAME_FOUND) {
 	    reiserfs_warning ("zam-7002:" __FUNCTION__ ": \"reiserfs_find_entry\" has returned"
                               " unexpected value (%d)\n", retval);
@@ -470,7 +477,7 @@
     if (gen_number != 0) {	/* we need to re-search for the insertion point */
       if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
             reiserfs_warning ("vs-7032: reiserfs_add_entry: "
-                            "entry with this key (%k) already exists\n", &entry_key);
+                            "entry with this key (%K) already exists\n", &entry_key);
 
 	    if (buffer != small_buf)
 		reiserfs_kfree (buffer, buflen, dir->i_sb);
@@ -715,10 +722,14 @@
     windex = push_journal_writer("reiserfs_rmdir") ;
 
     de.de_gen_number_bit_string = 0;
-    if (reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de) == NAME_NOT_FOUND) {
+    if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
 	retval = -ENOENT;
 	goto end_rmdir;
+    } else if ( retval == IO_ERROR) {
+	retval = -EIO;
+	goto end_rmdir;
     }
+
     inode = dentry->d_inode;
 
     reiserfs_update_inode_transaction(inode) ;
@@ -800,9 +811,12 @@
     windex = push_journal_writer("reiserfs_unlink") ;
 	
     de.de_gen_number_bit_string = 0;
-    if (reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de) == NAME_NOT_FOUND) {
+    if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
 	retval = -ENOENT;
 	goto end_unlink;
+    } else if (retval == IO_ERROR) {
+	retval = -EIO;
+	goto end_unlink;
     }
 
     reiserfs_update_inode_transaction(inode) ;
@@ -881,7 +895,7 @@
 	return -ENAMETOOLONG;
     }
   
-    name = kmalloc (item_len, GFP_NOFS);
+    name = reiserfs_kmalloc (item_len, GFP_NOFS, dir->i_sb);
     if (!name) {
 	iput(inode) ;
 	return -ENOMEM;
@@ -894,7 +908,7 @@
 
     inode = reiserfs_new_inode (&th, dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
 				inode, &retval);
-    kfree (name);
+    reiserfs_kfree (name, item_len, dir->i_sb);
     if (inode == 0) { /* reiserfs_new_inode iputs for us */
 	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
@@ -1065,8 +1079,10 @@
     retval = reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len,
 				  &old_entry_path, &old_de);
     pathrelse (&old_entry_path);
+    if (retval == IO_ERROR)
+	return -EIO;
+
     if (retval != NAME_FOUND || old_de.de_objectid != old_inode->i_ino) {
-	// FIXME: IO error is possible here
 	return -ENOENT;
     }
 
@@ -1138,6 +1154,8 @@
 	new_de.de_gen_number_bit_string = 0;
 	retval = reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
 				      &new_entry_path, &new_de);
+	// reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from
+        // reiserfs_add_entry above, and we'll catch any i/o errors before we get here.
 	if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND)
 	    BUG ();
 
diff -urN linux-2.4.19-pre2/fs/reiserfs/objectid.c linux-2.4.19-pre3/fs/reiserfs/objectid.c
--- linux-2.4.19-pre2/fs/reiserfs/objectid.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/objectid.c	Mon Mar 11 14:13:30 2002
@@ -5,6 +5,7 @@
 #include <linux/config.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/reiserfs_fs.h>
 
@@ -196,6 +197,10 @@
     /* set the max size so we don't overflow later */
     disk_sb->s_oid_maxsize = cpu_to_le16(new_size) ;
 
+    /* Zero out label and generate random UUID */
+    memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label)) ;
+    generate_random_uuid(disk_sb->s_uuid);
+
     /* finally, zero out the unused chunk of the new super */
     memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused)) ;
     return 0 ;
diff -urN linux-2.4.19-pre2/fs/reiserfs/prints.c linux-2.4.19-pre3/fs/reiserfs/prints.c
--- linux-2.4.19-pre2/fs/reiserfs/prints.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/prints.c	Mon Mar 11 14:13:30 2002
@@ -477,6 +477,17 @@
     return 0;
 }
 
+char * reiserfs_hashname(int code)
+{
+    if ( code == YURA_HASH)
+	return "rupasov";
+    if ( code == TEA_HASH)
+	return "tea";
+    if ( code == R5_HASH)
+	return "r5";
+
+    return "unknown";
+}
 /* return 1 if this is not super block */
 static int print_super_block (struct buffer_head * bh)
 {
@@ -519,8 +530,7 @@
     printk ("Filesystem state %s\n", 
 	    (sb_state(rs) == REISERFS_VALID_FS) ? "VALID" : "ERROR");
     printk ("Hash function \"%s\"\n",
-            sb_hash_function_code(rs) == TEA_HASH ? "tea" :
-	    ( sb_hash_function_code(rs) == YURA_HASH ? "rupasov" : (sb_hash_function_code(rs) == R5_HASH ? "r5" : "unknown")));
+            reiserfs_hashname(sb_hash_function_code(rs)));
 
     printk ("Tree height %d\n", sb_tree_height(rs));
     return 0;
diff -urN linux-2.4.19-pre2/fs/reiserfs/procfs.c linux-2.4.19-pre3/fs/reiserfs/procfs.c
--- linux-2.4.19-pre2/fs/reiserfs/procfs.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/procfs.c	Mon Mar 11 14:13:30 2002
@@ -172,6 +172,12 @@
 			"search_by_key_fs_changed: \t%lu\n"
 			"search_by_key_restarted: \t%lu\n"
 			
+			"insert_item_restarted: \t%lu\n"
+			"paste_into_item_restarted: \t%lu\n"
+			"cut_from_item_restarted: \t%lu\n"
+			"delete_solid_item_restarted: \t%lu\n"
+			"delete_item_restarted: \t%lu\n"
+
 			"leaked_oid: \t%lu\n"
 			"leaves_removable: \t%lu\n",
 
@@ -208,6 +214,13 @@
 			SFP( search_by_key ),
 			SFP( search_by_key_fs_changed ),
 			SFP( search_by_key_restarted ),
+
+			SFP( insert_item_restarted ),
+			SFP( paste_into_item_restarted ),
+			SFP( cut_from_item_restarted ),
+			SFP( delete_solid_item_restarted ),
+			SFP( delete_item_restarted ),
+
 			SFP( leaked_oid ),
 			SFP( leaves_removable ) );
 
@@ -341,6 +354,7 @@
 	struct reiserfs_sb_info *sb_info;
 	struct reiserfs_super_block *rs;
 	int hash_code;
+	__u32 flags;
 	int len = 0;
     
 	sb = procinfo_prologue( ( kdev_t ) ( long ) data );
@@ -349,6 +363,7 @@
 	sb_info = &sb->u.reiserfs_sb;
 	rs = sb_info -> s_rs;
 	hash_code = DFL( s_hash_function_code );
+	flags = DFL( s_flags );
 
 	len += sprintf( &buffer[ len ], 
 			"block_count: \t%i\n"
@@ -362,7 +377,8 @@
 			"hash: \t%s\n"
 			"tree_height: \t%i\n"
 			"bmap_nr: \t%i\n"
-			"version: \t%i\n",
+			"version: \t%i\n"
+			"flags: \t%x[%s]\n",
 
 			DFL( s_block_count ),
 			DFL( s_free_blocks ),
@@ -378,7 +394,10 @@
 			( hash_code == UNSET_HASH ) ? "unset" : "unknown",
 			DF( s_tree_height ),
 			DF( s_bmap_nr ),
-			DF( s_version ) );
+			DF( s_version ),
+			flags, 
+			( flags & reiserfs_attrs_cleared ) 
+			? "attrs_cleared" : "" );
 
 	procinfo_epilogue( sb );
 	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
diff -urN linux-2.4.19-pre2/fs/reiserfs/stree.c linux-2.4.19-pre3/fs/reiserfs/stree.c
--- linux-2.4.19-pre2/fs/reiserfs/stree.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/stree.c	Mon Mar 11 14:13:30 2002
@@ -166,7 +166,7 @@
     if (cpu_key_k_offset (key1) > cpu_key_k_offset (key2))
 	return 1;
 
-    reiserfs_warning ("comp_cpu_keys: type are compared for %k and %k\n",
+    reiserfs_warning ("comp_cpu_keys: type are compared for %K and %K\n",
 		      key1, key2);
 
     if (cpu_key_k_type (key1) < cpu_key_k_type (key2))
@@ -524,6 +524,10 @@
     ih = (struct item_head *)(buf + BLKH_SIZE);
     prev_location = blocksize;
     for (i = 0; i < nr; i ++, ih ++) {
+	if ( le_ih_k_type(ih) == TYPE_ANY) {
+	    reiserfs_warning ("is_leaf: wrong item type for item %h\n",ih);
+	    return 0;
+	}
 	if (ih_location (ih) >= blocksize || ih_location (ih) < IH_SIZE * nr) {
 	    reiserfs_warning ("is_leaf: item location seems wrong: %h\n", ih);
 	    return 0;
@@ -1242,6 +1246,8 @@
 	if ( n_ret_value != REPEAT_SEARCH )
 	    break;
 
+	PROC_INFO_INC( p_s_sb, delete_item_restarted );
+
 	// file system changed, repeat search
 	n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
 	if (n_ret_value == IO_ERROR)
@@ -1339,8 +1345,10 @@
 	}
 	if (retval != ITEM_FOUND) {
 	    pathrelse (&path);
-	    reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found",
-			      key);
+	    // No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir
+	    if ( !( (unsigned long long) GET_HASH_VALUE (le_key_k_offset (le_key_version (key), key)) == 0 && \
+		 GET_GENERATION_NUMBER (le_key_k_offset (le_key_version (key), key)) == 1 ) )
+		reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found", key);
 	    break;
 	}
 	if (!tb_init) {
@@ -1350,8 +1358,10 @@
 	}
 
 	retval = fix_nodes (M_DELETE, &tb, NULL, 0);
-	if (retval == REPEAT_SEARCH)
+	if (retval == REPEAT_SEARCH) {
+	    PROC_INFO_INC( th -> t_super, delete_solid_item_restarted );
 	    continue;
+	}
 
 	if (retval == CARRY_ON) {
 	    do_balance (&tb, 0, 0, M_DELETE);
@@ -1523,7 +1533,7 @@
 	    set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);
 	    if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){
 		print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);
-		reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%k)", p_s_item_key);
+		reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)", p_s_item_key);
 	    }
 	    continue;
 	}
@@ -1538,6 +1548,8 @@
       	if ( n_ret_value != REPEAT_SEARCH )
 	    break;
 	
+	PROC_INFO_INC( p_s_sb, cut_from_item_restarted );
+
 	n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
 	if (n_ret_value == POSITION_FOUND)
 	    continue;
@@ -1716,7 +1728,7 @@
 	}
 
 	RFALSE( n_deleted > n_file_size,
-		"PAP-5670: reiserfs_truncate_file returns too big number: deleted %d, file_size %lu, item_key %k",
+		"PAP-5670: reiserfs_truncate_file returns too big number: deleted %d, file_size %lu, item_key %K",
 		n_deleted, n_file_size, &s_item_key);
 
 	/* Change key to search the last file item. */
@@ -1805,6 +1817,7 @@
     
     while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) {
 	/* file system changed while we were in the fix_nodes */
+	PROC_INFO_INC( th -> t_super, paste_into_item_restarted );
 	retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path);
 	if (retval == IO_ERROR) {
 	    retval = -EIO ;
@@ -1855,6 +1868,7 @@
 
     while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) {
 	/* file system changed while we were in the fix_nodes */
+	PROC_INFO_INC( th -> t_super, insert_item_restarted );
 	retval = search_item (th->t_super, key, p_s_path);
 	if (retval == IO_ERROR) {
 	    retval = -EIO;
diff -urN linux-2.4.19-pre2/fs/reiserfs/super.c linux-2.4.19-pre3/fs/reiserfs/super.c
--- linux-2.4.19-pre2/fs/reiserfs/super.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/reiserfs/super.c	Mon Mar 11 14:13:30 2002
@@ -207,7 +207,7 @@
         }
  
         iput (inode);
-        reiserfs_warning ("done\n");
+        printk ("done\n");
         done ++;
     }
     s -> u.reiserfs_sb.s_is_unlinked_ok = 0;
@@ -269,7 +269,8 @@
     /* look for its place in the tree */
     retval = search_item (inode->i_sb, &key, &path);
     if (retval != ITEM_NOT_FOUND) {
-	reiserfs_warning ("vs-2100: add_save_link:"
+	if ( retval != -ENOSPC )
+	    reiserfs_warning ("vs-2100: add_save_link:"
 			  "search_by_key (%K) returned %d\n", &key, retval);
 	pathrelse (&path);
 	return;
@@ -280,10 +281,11 @@
 
     /* put "save" link inot tree */
     retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
-    if (retval)
-	reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
+    if (retval) {
+	if (retval != -ENOSPC)
+	    reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
 			  retval);
-    else {
+    } else {
 	if( truncate )
 	    inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
 	else
@@ -488,6 +490,8 @@
 	  	printk("reiserfs: hash option requires a value\n");
 		return 0 ;
 	    }
+	} else if (!strcmp (this_char, "attrs")) {
+	    set_bit (REISERFS_ATTRS, mount_options);
 	} else {
 	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
 	    return 0;
@@ -502,6 +506,24 @@
 }
 
 
+static void handle_attrs( struct super_block *s )
+{
+	struct reiserfs_super_block * rs;
+
+	if( reiserfs_attrs( s ) ) {
+		rs = SB_DISK_SUPER_BLOCK (s);
+		if( old_format_only(s) ) {
+			reiserfs_warning( "reiserfs: cannot support attributes on 3.5.x disk format\n" );
+			s -> u.reiserfs_sb.s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
+			return;
+		}
+		if( !( le32_to_cpu( rs -> s_flags ) & reiserfs_attrs_cleared ) ) {
+				reiserfs_warning( "reiserfs: cannot support attributes until flag is set in super-block\n" );
+				s -> u.reiserfs_sb.s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
+		}
+	}
+}
+
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -514,13 +536,28 @@
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
   unsigned long blocks;
-  unsigned long mount_options;
+  unsigned long mount_options = 0;
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
   if (!parse_options(data, &mount_options, &blocks))
   	return 0;
 
+#define SET_OPT( opt, bits, super )					\
+    if( ( bits ) & ( 1 << ( opt ) ) )					\
+	    ( super ) -> u.reiserfs_sb.s_mount_opt |= ( 1 << ( opt ) )
+
+  /* set options in the super-block bitmask */
+  SET_OPT( NOTAIL, mount_options, s );
+  SET_OPT( REISERFS_NO_BORDER, mount_options, s );
+  SET_OPT( REISERFS_NO_UNHASHED_RELOCATION, mount_options, s );
+  SET_OPT( REISERFS_HASHED_RELOCATION, mount_options, s );
+  SET_OPT( REISERFS_TEST4, mount_options, s );
+  SET_OPT( REISERFS_ATTRS, mount_options, s );
+#undef SET_OPT
+
+  handle_attrs( s );
+
   if(blocks) {
       int rc = reiserfs_resize(s, blocks);
       if (rc != 0)
@@ -572,28 +609,30 @@
 
 static int read_bitmaps (struct super_block * s)
 {
-    int i, bmp, dl ;
-    struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK(s);
+    int i, bmp;
 
-    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
+    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * SB_BMAP_NR(s), GFP_NOFS, s);
     if (SB_AP_BITMAP (s) == 0)
+      return 1;
+    for (i = 0, bmp = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
+ 	 i < SB_BMAP_NR(s); i++, bmp = s->s_blocksize * 8 * i) {
+      SB_AP_BITMAP (s)[i] = getblk (s->s_dev, bmp, s->s_blocksize);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i]))
+	ll_rw_block(READ, 1, SB_AP_BITMAP(s) + i); 
+    }
+    for (i = 0; i < SB_BMAP_NR(s); i++) {
+      wait_on_buffer(SB_AP_BITMAP (s)[i]);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
+	reiserfs_warning("sh-2029: reiserfs read_bitmaps: "
+			 "bitmap block (#%lu) reading failed\n",
+			 SB_AP_BITMAP(s)[i]->b_blocknr);
+	for (i = 0; i < SB_BMAP_NR(s); i++)
+	  brelse(SB_AP_BITMAP(s)[i]);
+	reiserfs_kfree(SB_AP_BITMAP(s), sizeof(struct buffer_head *) * SB_BMAP_NR(s), s);
+	SB_AP_BITMAP(s) = NULL;
 	return 1;
-    memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
-
-    /* reiserfs leaves the first 64k unused so that any partition
-       labeling scheme currently used will have enough space. Then we
-       need one block for the super.  -Hans */
-    bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;	/* first of bitmap blocks */
-    SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp, s->s_blocksize);
-    if(!SB_AP_BITMAP(s)[0])
-	return 1;
-    for (i = 1, bmp = dl = s->s_blocksize * 8; i < sb_bmap_nr(rs); i ++) {
-	SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp, s->s_blocksize);
-	if (!SB_AP_BITMAP (s)[i])
-	    return 1;
-	bmp += dl;
-    }
-
+      }
+    }   
     return 0;
 }
 
@@ -704,8 +743,18 @@
 	       "It must not be of this format type.\n", bh->b_blocknr) ;
 	return 1 ;
     }
+
+    if ( rs->s_root_block == -1 ) {
+	brelse(bh) ;
+	printk("dev %s: Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
+	       "reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
+	       "get newer reiserfsprogs package\n", kdevname (s->s_dev));
+	return 1;
+    }
+
     SB_BUFFER_WITH_SB (s) = bh;
     SB_DISK_SUPER_BLOCK (s) = rs;
+
     s->s_op = &reiserfs_sops;
 
     /* new format is limited by the 32 bit wide i_blocks field, want to
@@ -760,7 +809,9 @@
 
     inode = s->s_root->d_inode;
 
-    while (1) {
+    do { // Some serious "goto"-hater was there ;)
+	u32 teahash, r5hash, yurahash;
+
 	make_cpu_key (&key, inode, ~0, TYPE_DIRENTRY, 3);
 	retval = search_by_entry_key (s, &key, &path, &de);
 	if (retval == IO_ERROR) {
@@ -779,20 +830,30 @@
 	                     "is using the default hash\n");
 	    break;
 	}
-	if (GET_HASH_VALUE(yura_hash (de.de_name, de.de_namelen)) == 
-	    GET_HASH_VALUE(keyed_hash (de.de_name, de.de_namelen))) {
-	    reiserfs_warning ("reiserfs: Could not detect hash function "
-			      "please mount with -o hash={tea,rupasov,r5}\n") ;
-	    hash = UNSET_HASH ;
+	r5hash=GET_HASH_VALUE (r5_hash (de.de_name, de.de_namelen));
+	teahash=GET_HASH_VALUE (keyed_hash (de.de_name, de.de_namelen));
+	yurahash=GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen));
+	if ( ( (teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) ) ||
+	     ( (teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ||
+	     ( (r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ) {
+	    reiserfs_warning("reiserfs: Unable to automatically detect hash"
+		"function for device %s\n"
+		"please mount with -o hash={tea,rupasov,r5}\n", kdevname (s->s_dev));
+	    hash = UNSET_HASH;
 	    break;
 	}
-	if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) ==
-	    GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen)))
+	if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == yurahash)
 	    hash = YURA_HASH;
-	else
+	else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == teahash)
 	    hash = TEA_HASH;
-	break;
-    }
+	else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == r5hash)
+	    hash = R5_HASH;
+	else {
+	    reiserfs_warning("reiserfs: Unrecognised hash function for "
+			     "device %s\n", kdevname (s->s_dev));
+	    hash = UNSET_HASH;
+	}
+    } while (0);
 
     pathrelse (&path);
     return hash;
@@ -817,16 +878,16 @@
 	** mount options 
 	*/
 	if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
-	    printk("REISERFS: Error, tea hash detected, "
-		   "unable to force rupasov hash\n") ;
+	    printk("REISERFS: Error, %s hash detected, "
+		   "unable to force rupasov hash\n", reiserfs_hashname(code)) ;
 	    code = UNSET_HASH ;
 	} else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
-	    printk("REISERFS: Error, rupasov hash detected, "
-		   "unable to force tea hash\n") ;
+	    printk("REISERFS: Error, %s hash detected, "
+		   "unable to force tea hash\n", reiserfs_hashname(code)) ;
 	    code = UNSET_HASH ;
 	} else if (reiserfs_r5_hash(s) && code != R5_HASH) {
-	    printk("REISERFS: Error, r5 hash detected, "
-		   "unable to force r5 hash\n") ;
+	    printk("REISERFS: Error, %s hash detected, "
+		   "unable to force r5 hash\n", reiserfs_hashname(code)) ;
 	    code = UNSET_HASH ;
 	} 
     } else { 
@@ -934,6 +995,8 @@
 	    old_format = 1;
     }
 
+    rs = SB_DISK_SUPER_BLOCK (s);
+
     s->u.reiserfs_sb.s_mount_state = SB_REISERFS_STATE(s);
     s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ;
 
@@ -1034,6 +1097,8 @@
     // mark hash in super block: it could be unset. overwrite should be ok
     set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) );
 
+    handle_attrs( s );
+
     reiserfs_proc_info_init( s );
     reiserfs_proc_register( s, "version", reiserfs_version_in_proc );
     reiserfs_proc_register( s, "super", reiserfs_super_in_proc );
diff -urN linux-2.4.19-pre2/fs/reiserfs/tail_conversion.c linux-2.4.19-pre3/fs/reiserfs/tail_conversion.c
--- linux-2.4.19-pre2/fs/reiserfs/tail_conversion.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/fs/reiserfs/tail_conversion.c	Mon Mar 11 14:13:30 2002
@@ -49,9 +49,13 @@
     make_cpu_key (&end_key, inode, tail_offset, TYPE_INDIRECT, 4);
 
     // FIXME: we could avoid this 
-    if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND )
-	reiserfs_panic (sb, "PAP-14030: direct2indirect: "
-			"pasted or inserted byte exists in the tree");
+    if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND ) {
+	reiserfs_warning ("PAP-14030: direct2indirect: "
+			"pasted or inserted byte exists in the tree %K. "
+			"Use fsck to repair.\n", &end_key);
+	pathrelse(path);
+	return -EIO;
+    }
     
     p_le_ih = PATH_PITEM_HEAD (path);
 
@@ -90,10 +94,10 @@
            last item of the file */
 	if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND )
 	    reiserfs_panic (sb, "PAP-14050: direct2indirect: "
-			    "direct item (%k) not found", &end_key);
+			    "direct item (%K) not found", &end_key);
 	p_le_ih = PATH_PITEM_HEAD (path);
 	RFALSE( !is_direct_le_ih (p_le_ih),
-	        "vs-14055: direct item expected(%k), found %h",
+	        "vs-14055: direct item expected(%K), found %h",
                 &end_key, p_le_ih);
         tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
             + ih_item_len(p_le_ih) - 1;
@@ -227,7 +231,7 @@
 	/* re-search indirect item */
 	if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND )
 	    reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: "
-			   "item to be converted %k does not exist", p_s_item_key);
+			   "item to be converted %K does not exist", p_s_item_key);
 	copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
 #ifdef CONFIG_REISERFS_CHECK
 	pos = le_ih_k_offset (&s_ih) - 1 + 
diff -urN linux-2.4.19-pre2/fs/smbfs/cache.c linux-2.4.19-pre3/fs/smbfs/cache.c
--- linux-2.4.19-pre2/fs/smbfs/cache.c	Tue Oct  2 17:03:34 2001
+++ linux-2.4.19-pre3/fs/smbfs/cache.c	Mon Mar 11 14:13:30 2002
@@ -84,7 +84,7 @@
 	struct list_head *next;
 
 	if (d_validate(dent, parent)) {
-		if (dent->d_name.len <= SMB_MAXPATHLEN &&
+		if (dent->d_name.len <= SMB_MAXNAMELEN &&
 		    (unsigned long)dent->d_fsdata == fpos) {
 			if (!dent->d_inode) {
 				dput(dent);
diff -urN linux-2.4.19-pre2/fs/smbfs/proc.c linux-2.4.19-pre3/fs/smbfs/proc.c
--- linux-2.4.19-pre2/fs/smbfs/proc.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre3/fs/smbfs/proc.c	Mon Mar 11 14:13:30 2002
@@ -109,6 +109,22 @@
 	return ilen;
 }
 
+static inline int write_char(unsigned char ch, char *output, int olen)
+{
+	if (olen < 4)
+		return -ENAMETOOLONG;
+	sprintf(output, ":x%02x", ch);
+	return 4;
+}
+
+static inline int write_unichar(wchar_t ch, char *output, int olen)
+{
+	if (olen < 5)
+		return -ENAMETOOLONG;
+	sprintf(output, ":%04x", ch);
+	return 5;
+}
+
 /* convert from one "codepage" to another (possibly being utf8). */
 static int convert_cp(char *output, int olen,
 		      const char *input, int ilen,
@@ -119,20 +135,26 @@
 	int n;
 	wchar_t ch;
 
-	if (!nls_from || !nls_to) {
-		PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);
-		return convert_memcpy(output, olen, input, ilen, NULL, NULL);
-	}
-
 	while (ilen > 0) {
 		/* convert by changing to unicode and back to the new cp */
 		n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
-		if (n < 0)
+		if (n == -EINVAL) {
+			ilen--;
+			n = write_char(*input++, output, olen);
+			if (n < 0)
+				goto fail;
+			output += n;
+			olen -= n;
+			len += n;
+			continue;
+		} else if (n < 0)
 			goto fail;
 		input += n;
 		ilen -= n;
 
 		n = nls_to->uni2char(ch, output, olen);
+		if (n == -EINVAL)
+			n = write_unichar(ch, output, olen);
 		if (n < 0)
 			goto fail;
 		output += n;
@@ -226,8 +248,8 @@
 	if (maxlen < 2)
 		return -ENAMETOOLONG;
 
-	if (maxlen > SMB_MAXNAMELEN + 1)
-		maxlen = SMB_MAXNAMELEN + 1;
+	if (maxlen > SMB_MAXPATHLEN + 1)
+		maxlen = SMB_MAXPATHLEN + 1;
 
 	if (entry == NULL)
 		goto test_name_and_out;
@@ -1579,12 +1601,16 @@
 	}
 #endif
 
-	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     qname->name, len,
-				     server->remote_nls, server->local_nls);
-	qname->name = server->name_buf;
+	qname->len = 0;
+	len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+			    qname->name, len,
+			    server->remote_nls, server->local_nls);
+	if (len > 0) {
+		qname->len = len;
+		qname->name = server->name_buf;
+		DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);
+	}
 
-	DEBUG1("len=%d, name=%.*s\n", qname->len, qname->len, qname->name);
 	return p + 22;
 }
 
@@ -1700,7 +1726,8 @@
 		for (i = 0; i < count; i++) {
 			p = smb_decode_short_dirent(server, p, 
 						    &qname, &fattr);
-
+			if (qname.len == 0)
+				continue;
 			if (entries_seen == 2 && qname.name[0] == '.') {
 				if (qname.len == 1)
 					continue;
@@ -1737,6 +1764,7 @@
 {
 	char *result;
 	unsigned int len = 0;
+	int n;
 	__u16 date, time;
 
 	/*
@@ -1812,10 +1840,14 @@
 	}
 #endif
 
-	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     qname->name, len,
-				     server->remote_nls, server->local_nls);
-	qname->name = server->name_buf;
+	qname->len = 0;
+	n = server->convert(server->name_buf, SMB_MAXNAMELEN,
+			    qname->name, len,
+			    server->remote_nls, server->local_nls);
+	if (n > 0) {
+		qname->len = n;
+		qname->name = server->name_buf;
+	}
 
 out:
 	return result;
@@ -1881,7 +1913,7 @@
 	 */
 	mask = param + 12;
 
-	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dir, &star);
+	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto unlock_return;
@@ -2030,6 +2062,8 @@
 
 			p = smb_decode_long_dirent(server, p, info_level,
 						   &qname, &fattr);
+			if (qname.len == 0)
+				continue;
 
 			/* ignore . and .. from the server */
 			if (entries_seen == 2 && qname.name[0] == '.') {
@@ -2088,7 +2122,7 @@
 	int mask_len, result;
 
 retry:
-	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL);
+	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry, NULL);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto out;
@@ -2214,7 +2248,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;
@@ -2464,7 +2498,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;
diff -urN linux-2.4.19-pre2/fs/ufs/super.c linux-2.4.19-pre3/fs/ufs/super.c
--- linux-2.4.19-pre2/fs/ufs/super.c	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/fs/ufs/super.c	Mon Mar 11 14:13:30 2002
@@ -597,7 +597,7 @@
 	}
 	
 again:	
-	if (!set_blocksize (sb->s_dev, block_size)) {
+	if (set_blocksize (sb->s_dev, block_size)) {
 		printk(KERN_ERR "UFS: failed to set blocksize\n");
 		goto failed;
 	}
diff -urN linux-2.4.19-pre2/include/asm-alpha/ide.h linux-2.4.19-pre3/include/asm-alpha/ide.h
--- linux-2.4.19-pre2/include/asm-alpha/ide.h	Wed May 24 08:40:41 2000
+++ linux-2.4.19-pre3/include/asm-alpha/ide.h	Mon Mar 11 14:13:30 2002
@@ -91,7 +91,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-alpha/pgalloc.h linux-2.4.19-pre3/include/asm-alpha/pgalloc.h
--- linux-2.4.19-pre2/include/asm-alpha/pgalloc.h	Thu May 24 15:20:18 2001
+++ linux-2.4.19-pre3/include/asm-alpha/pgalloc.h	Mon Mar 11 14:13:30 2002
@@ -70,8 +70,7 @@
 }
 
 /* We need to flush the userspace icache after setting breakpoints in
-   ptrace.  I don't think it's needed in do_swap_page, or do_no_page,
-   but I don't know how to get rid of it either.
+   ptrace.
 
    Instead of indiscriminately using imb, take advantage of the fact
    that icache entries are tagged with the ASN and load a new mm context.  */
@@ -79,7 +78,8 @@
 
 #ifndef CONFIG_SMP
 static inline void
-flush_icache_page(struct vm_area_struct *vma, struct page *page)
+flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+			unsigned long addr, int len)
 {
 	if (vma->vm_flags & VM_EXEC) {
 		struct mm_struct *mm = vma->vm_mm;
@@ -90,9 +90,13 @@
 	}
 }
 #else
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+		struct page *page, unsigned long addr, int len);
 #endif
 
+/* this is used only in do_no_page and do_swap_page */
+#define flush_icache_page(vma, page)	flush_icache_user_range((vma), (page), 0, 0)
+
 /*
  * Flush just one page in the current TLB set.
  * We need to be very careful about the icache here, there
diff -urN linux-2.4.19-pre2/include/asm-alpha/siginfo.h linux-2.4.19-pre3/include/asm-alpha/siginfo.h
--- linux-2.4.19-pre2/include/asm-alpha/siginfo.h	Wed May 24 18:38:26 2000
+++ linux-2.4.19-pre3/include/asm-alpha/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-alpha/unistd.h linux-2.4.19-pre3/include/asm-alpha/unistd.h
--- linux-2.4.19-pre2/include/asm-alpha/unistd.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre3/include/asm-alpha/unistd.h	Mon Mar 11 14:13:30 2002
@@ -318,6 +318,7 @@
 #define __NR_gettid			378
 #define __NR_readahead			379
 #define __NR_security			380 /* syscall for security modules */
+#define __NR_tkill			381
 
 #if defined(__GNUC__)
 
diff -urN linux-2.4.19-pre2/include/asm-arm/ide.h linux-2.4.19-pre3/include/asm-arm/ide.h
--- linux-2.4.19-pre2/include/asm-arm/ide.h	Thu Jun 17 01:11:35 1999
+++ linux-2.4.19-pre3/include/asm-arm/ide.h	Mon Mar 11 14:13:30 2002
@@ -30,7 +30,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-arm/siginfo.h linux-2.4.19-pre3/include/asm-arm/siginfo.h
--- linux-2.4.19-pre2/include/asm-arm/siginfo.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre3/include/asm-arm/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL        -6              /* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-cris/ide.h linux-2.4.19-pre3/include/asm-cris/ide.h
--- linux-2.4.19-pre2/include/asm-cris/ide.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.19-pre3/include/asm-cris/ide.h	Mon Mar 11 14:13:30 2002
@@ -97,7 +97,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 /* some configuration options we don't need */
 
diff -urN linux-2.4.19-pre2/include/asm-cris/pgtable.h linux-2.4.19-pre3/include/asm-cris/pgtable.h
--- linux-2.4.19-pre2/include/asm-cris/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-cris/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -125,6 +125,7 @@
 #define flush_dcache_page(page)                 do { } while (0)
 #define flush_icache_range(start, end)          do { } while (0)
 #define flush_icache_page(vma,pg)               do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /*
  * TLB flushing (implemented in arch/cris/mm/tlb.c):
diff -urN linux-2.4.19-pre2/include/asm-cris/siginfo.h linux-2.4.19-pre3/include/asm-cris/siginfo.h
--- linux-2.4.19-pre2/include/asm-cris/siginfo.h	Thu Feb  8 16:32:44 2001
+++ linux-2.4.19-pre3/include/asm-cris/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-cris/unistd.h linux-2.4.19-pre3/include/asm-cris/unistd.h
--- linux-2.4.19-pre2/include/asm-cris/unistd.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre3/include/asm-cris/unistd.h	Mon Mar 11 14:13:30 2002
@@ -230,6 +230,7 @@
 #define __NR_security           223     /* syscall for security modules */
 #define __NR_gettid             224
 #define __NR_readahead          225
+#define __NR_tkill              226
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
diff -urN linux-2.4.19-pre2/include/asm-i386/fixmap.h linux-2.4.19-pre3/include/asm-i386/fixmap.h
--- linux-2.4.19-pre2/include/asm-i386/fixmap.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre3/include/asm-i386/fixmap.h	Mon Mar 11 14:13:30 2002
@@ -65,6 +65,11 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+	__end_of_permanent_fixed_addresses,
+	/* temporary boot-time mappings, used before ioremap() is functional */
+#define NR_FIX_BTMAPS	16
+	FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+	FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
 	__end_of_fixed_addresses
 };
 
@@ -86,8 +91,8 @@
  * at the top of mem..
  */
 #define FIXADDR_TOP	(0xffffe000UL)
-#define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
-#define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
+#define __FIXADDR_SIZE	(__end_of_permanent_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START	(FIXADDR_TOP - __FIXADDR_SIZE)
 
 #define __fix_to_virt(x)	(FIXADDR_TOP - ((x) << PAGE_SHIFT))
 
diff -urN linux-2.4.19-pre2/include/asm-i386/ide.h linux-2.4.19-pre3/include/asm-i386/ide.h
--- linux-2.4.19-pre2/include/asm-i386/ide.h	Thu Nov 22 11:46:58 2001
+++ linux-2.4.19-pre3/include/asm-i386/ide.h	Mon Mar 11 14:13:30 2002
@@ -95,7 +95,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-i386/io.h linux-2.4.19-pre3/include/asm-i386/io.h
--- linux-2.4.19-pre2/include/asm-i386/io.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-i386/io.h	Mon Mar 11 14:13:30 2002
@@ -60,15 +60,37 @@
 //#define __io_phys(x) __pa(x)
 #endif
 
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
+/**
+ *	virt_to_phys	-	map virtual addresses to physical
+ *	@address: address to remap
+ *
+ *	The returned physical address is the physical (CPU) mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses directly mapped or allocated via kmalloc. 
+ *
+ *	This function does not give bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
  */
+ 
 static inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
+/**
+ *	phys_to_virt	-	map physical address to virtual
+ *	@address: address to remap
+ *
+ *	The returned virtual address is a current CPU mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses that have a kernel mapping
+ *
+ *	This function does not handle bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
+ */
+
 static inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
@@ -81,16 +103,43 @@
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
+/**
+ *	ioremap		-	map bus memory into CPU space
+ *	@offset:	bus address of the memory
+ *	@size:		size of the resource to map
+ *
+ *	ioremap performs a platform specific sequence of operations to
+ *	make bus memory CPU accessible via the readb/readw/readl/writeb/
+ *	writew/writel functions and the other mmio helpers. The returned
+ *	address is not guaranteed to be usable directly as a virtual
+ *	address. 
+ */
+ 
 static inline void * ioremap (unsigned long offset, unsigned long size)
 {
 	return __ioremap(offset, size, 0);
 }
 
-/*
- * This one maps high address device memory and turns off caching for that area.
- * it's useful if some control registers are in such an area and write combining
- * or read caching is not desirable:
+/**
+ *	ioremap_nocache		-	map bus memory into CPU space
+ *	@offset:	bus address of the memory
+ *	@size:		size of the resource to map
+ *
+ *	ioremap_nocache performs a platform specific sequence of operations to
+ *	make bus memory CPU accessible via the readb/readw/readl/writeb/
+ *	writew/writel functions and the other mmio helpers. The returned
+ *	address is not guaranteed to be usable directly as a virtual
+ *	address. 
+ *
+ *	This version of ioremap ensures that the memory is marked uncachable
+ *	on the CPU as well as honouring existing caching rules from things like
+ *	the PCI bus. Note that there are other caches and buffers on many 
+ *	busses. In paticular driver authors should read up on PCI writes
+ *
+ *	It's useful if some control registers are in such an area and
+ *	write combining or read caching is not desirable:
  */
+ 
 static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, _PAGE_PCD);
@@ -99,6 +148,14 @@
 extern void iounmap(void *addr);
 
 /*
+ * bt_ioremap() and bt_iounmap() are for temporary early boot-time
+ * mappings, before the real ioremap() is functional.
+ * A boot-time mapping is currently limited to at most 16 pages.
+ */
+extern void *bt_ioremap(unsigned long offset, unsigned long size);
+extern void bt_iounmap(void *addr, unsigned long size);
+
+/*
  * IO bus memory addresses are also 1:1 with the physical address
  */
 #define virt_to_bus virt_to_phys
@@ -158,6 +215,17 @@
 #define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),__io_virt(b),(c),(d))
 #define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
 
+/**
+ *	check_signature		-	find BIOS signatures
+ *	@io_addr: mmio address to check 
+ *	@signature:  signature block
+ *	@length: length of signature
+ *
+ *	Perform a signature comparison with the mmio address io_addr. This
+ *	address should have been obtained by ioremap.
+ *	Returns 1 on a match.
+ */
+ 
 static inline int check_signature(unsigned long io_addr,
 	const unsigned char *signature, int length)
 {
@@ -174,6 +242,20 @@
 	return retval;
 }
 
+/**
+ *	isa_check_signature		-	find BIOS signatures
+ *	@io_addr: mmio address to check 
+ *	@signature:  signature block
+ *	@length: length of signature
+ *
+ *	Perform a signature comparison with the ISA mmio address io_addr.
+ *	Returns 1 on a match.
+ *
+ *	This function is deprecated. New drivers should use ioremap and
+ *	check_signature.
+ */
+ 
+
 static inline int isa_check_signature(unsigned long io_addr,
 	const unsigned char *signature, int length)
 {
diff -urN linux-2.4.19-pre2/include/asm-i386/irq.h linux-2.4.19-pre3/include/asm-i386/irq.h
--- linux-2.4.19-pre2/include/asm-i386/irq.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre3/include/asm-i386/irq.h	Mon Mar 11 14:13:30 2002
@@ -23,7 +23,11 @@
  * Since vectors 0x00-0x1f are used/reserved for the CPU,
  * the usable vector space is 0x20-0xff (224 vectors)
  */
+#ifdef CONFIG_X86_IO_APIC
 #define NR_IRQS 224
+#else
+#define NR_IRQS 16
+#endif
 
 static __inline__ int irq_cannonicalize(int irq)
 {
diff -urN linux-2.4.19-pre2/include/asm-i386/msr.h linux-2.4.19-pre3/include/asm-i386/msr.h
--- linux-2.4.19-pre2/include/asm-i386/msr.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/include/asm-i386/msr.h	Mon Mar 11 14:13:30 2002
@@ -48,18 +48,12 @@
 #define MSR_IA32_UCODE_WRITE		0x79
 #define MSR_IA32_UCODE_REV		0x8b
 
-#define MSR_IA32_PERFCTR0		0xc1
-#define MSR_IA32_PERFCTR1		0xc2
-
 #define MSR_IA32_BBL_CR_CTL		0x119
 
 #define MSR_IA32_MCG_CAP		0x179
 #define MSR_IA32_MCG_STATUS		0x17a
 #define MSR_IA32_MCG_CTL		0x17b
 
-#define MSR_IA32_EVNTSEL0		0x186
-#define MSR_IA32_EVNTSEL1		0x187
-
 #define MSR_IA32_DEBUGCTLMSR		0x1d9
 #define MSR_IA32_LASTBRANCHFROMIP	0x1db
 #define MSR_IA32_LASTBRANCHTOIP		0x1dc
@@ -71,6 +65,11 @@
 #define MSR_IA32_MC0_ADDR		0x402
 #define MSR_IA32_MC0_MISC		0x403
 
+#define MSR_P6_PERFCTR0			0xc1
+#define MSR_P6_PERFCTR1			0xc2
+#define MSR_P6_EVNTSEL0			0x186
+#define MSR_P6_EVNTSEL1			0x187
+
 /* AMD Defined MSRs */
 #define MSR_K6_EFER			0xC0000080
 #define MSR_K6_STAR			0xC0000081
diff -urN linux-2.4.19-pre2/include/asm-i386/pgtable.h linux-2.4.19-pre3/include/asm-i386/pgtable.h
--- linux-2.4.19-pre2/include/asm-i386/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-i386/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -33,6 +33,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 #define __flush_tlb()							\
 	do {								\
diff -urN linux-2.4.19-pre2/include/asm-i386/siginfo.h linux-2.4.19-pre3/include/asm-i386/siginfo.h
--- linux-2.4.19-pre2/include/asm-i386/siginfo.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre3/include/asm-i386/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-i386/unistd.h linux-2.4.19-pre3/include/asm-i386/unistd.h
--- linux-2.4.19-pre2/include/asm-i386/unistd.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre3/include/asm-i386/unistd.h	Mon Mar 11 14:13:30 2002
@@ -243,6 +243,8 @@
 #define __NR_lremovexattr	236
 #define __NR_fremovexattr	237
 
+#define __NR_tkill		238
+
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
 #define __syscall_return(type, res) \
diff -urN linux-2.4.19-pre2/include/asm-ia64/ide.h linux-2.4.19-pre3/include/asm-ia64/ide.h
--- linux-2.4.19-pre2/include/asm-ia64/ide.h	Wed May 24 08:40:41 2000
+++ linux-2.4.19-pre3/include/asm-ia64/ide.h	Mon Mar 11 14:13:30 2002
@@ -101,7 +101,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-ia64/siginfo.h linux-2.4.19-pre3/include/asm-ia64/siginfo.h
--- linux-2.4.19-pre2/include/asm-ia64/siginfo.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-ia64/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -135,6 +135,7 @@
 #define SI_MESGQ	(-3)		/* sent by real time mesq state change */
 #define SI_ASYNCIO	(-4)		/* sent by AIO completion */
 #define SI_SIGIO	(-5)		/* sent by queued SIGIO */
+#define SI_TKILL	(-6)		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-ia64/unistd.h linux-2.4.19-pre3/include/asm-ia64/unistd.h
--- linux-2.4.19-pre2/include/asm-ia64/unistd.h	Fri Nov  9 14:26:17 2001
+++ linux-2.4.19-pre3/include/asm-ia64/unistd.h	Mon Mar 11 14:13:30 2002
@@ -206,6 +206,7 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
+#define __NR_tkill			1229
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -urN linux-2.4.19-pre2/include/asm-m68k/ide.h linux-2.4.19-pre3/include/asm-m68k/ide.h
--- linux-2.4.19-pre2/include/asm-m68k/ide.h	Mon Jun 11 19:15:27 2001
+++ linux-2.4.19-pre3/include/asm-m68k/ide.h	Mon Mar 11 14:13:30 2002
@@ -89,7 +89,19 @@
 		unsigned unit		: 1;	/* drive select number, 0 or 1 */
 		unsigned head		: 4;	/* always zeros here */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -urN linux-2.4.19-pre2/include/asm-m68k/pgalloc.h linux-2.4.19-pre3/include/asm-m68k/pgalloc.h
--- linux-2.4.19-pre2/include/asm-m68k/pgalloc.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.19-pre3/include/asm-m68k/pgalloc.h	Mon Mar 11 14:13:30 2002
@@ -127,6 +127,7 @@
 
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /* Push n pages at kernel virtual address and clear the icache */
 /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
diff -urN linux-2.4.19-pre2/include/asm-m68k/siginfo.h linux-2.4.19-pre3/include/asm-m68k/siginfo.h
--- linux-2.4.19-pre2/include/asm-m68k/siginfo.h	Mon Nov 27 17:11:26 2000
+++ linux-2.4.19-pre3/include/asm-m68k/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -117,6 +117,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-m68k/unistd.h linux-2.4.19-pre3/include/asm-m68k/unistd.h
--- linux-2.4.19-pre2/include/asm-m68k/unistd.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.19-pre3/include/asm-m68k/unistd.h	Mon Mar 11 14:13:30 2002
@@ -222,6 +222,8 @@
 #define __NR_setfsuid32		215
 #define __NR_setfsgid32		216
 #define __NR_getdents64		220
+#define __NR_gettid		221
+#define __NR_tkill		222
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -urN linux-2.4.19-pre2/include/asm-mips/ide.h linux-2.4.19-pre3/include/asm-mips/ide.h
--- linux-2.4.19-pre2/include/asm-mips/ide.h	Sun Sep  9 10:43:01 2001
+++ linux-2.4.19-pre3/include/asm-mips/ide.h	Mon Mar 11 14:13:30 2002
@@ -92,6 +92,26 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#ifdef __MIPSEB__
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+#else
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+#endif
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
diff -urN linux-2.4.19-pre2/include/asm-mips/pgtable.h linux-2.4.19-pre3/include/asm-mips/pgtable.h
--- linux-2.4.19-pre2/include/asm-mips/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -56,6 +56,8 @@
 
 #define flush_icache_range(start, end)	_flush_icache_range(start,end)
 #define flush_icache_page(vma, page) 	_flush_icache_page(vma, page)
+#define flush_icache_user_range(vma, page, addr, len)	\
+					_flush_icache_page((vma), (page))
 
 #define flush_cache_sigtramp(addr)	_flush_cache_sigtramp(addr)
 #ifdef CONFIG_VTAG_ICACHE
diff -urN linux-2.4.19-pre2/include/asm-mips/siginfo.h linux-2.4.19-pre3/include/asm-mips/siginfo.h
--- linux-2.4.19-pre2/include/asm-mips/siginfo.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -126,6 +126,7 @@
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-mips/unistd.h linux-2.4.19-pre3/include/asm-mips/unistd.h
--- linux-2.4.19-pre2/include/asm-mips/unistd.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips/unistd.h	Mon Mar 11 14:13:30 2002
@@ -245,11 +245,12 @@
 #define __NR_removexattr		(__NR_Linux + 233)
 #define __NR_lremovexattr		(__NR_Linux + 234)
 #define __NR_fremovexattr		(__NR_Linux + 235)
+#define __NR_tkill			(__NR_Linux + 236)
 
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls		235
+#define __NR_Linux_syscalls		236
 
 #ifndef _LANGUAGE_ASSEMBLY
 
diff -urN linux-2.4.19-pre2/include/asm-mips64/ide.h linux-2.4.19-pre3/include/asm-mips64/ide.h
--- linux-2.4.19-pre2/include/asm-mips64/ide.h	Sun Sep  9 10:43:02 2001
+++ linux-2.4.19-pre3/include/asm-mips64/ide.h	Mon Mar 11 14:13:30 2002
@@ -85,7 +85,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -urN linux-2.4.19-pre2/include/asm-mips64/pgtable.h linux-2.4.19-pre3/include/asm-mips64/pgtable.h
--- linux-2.4.19-pre2/include/asm-mips64/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips64/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -66,6 +66,8 @@
 #define flush_cache_page(vma,page)	do { } while(0)
 #define flush_page_to_ram(page)		do { } while(0)
 #define flush_icache_range(start, end)	_flush_cache_l1()
+#define flush_icache_user_range(vma, page, addr, len)	\
+					flush_icache_page((vma), (page))
 #define flush_icache_page(vma, page)					\
 do {									\
 	if ((vma)->vm_flags & VM_EXEC)					\
@@ -79,6 +81,8 @@
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
 #define flush_icache_range(start, end)	_flush_icache_range(start, end)
+#define flush_icache_user_range(vma, page, addr, len)	\
+					flush_icache_page((vma), (page))
 #define flush_icache_page(vma, page)	_flush_icache_page(vma, page)
 
 #endif /* !CONFIG_CPU_R10000 */
diff -urN linux-2.4.19-pre2/include/asm-mips64/siginfo.h linux-2.4.19-pre3/include/asm-mips64/siginfo.h
--- linux-2.4.19-pre2/include/asm-mips64/siginfo.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips64/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -127,6 +127,7 @@
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-mips64/unistd.h linux-2.4.19-pre3/include/asm-mips64/unistd.h
--- linux-2.4.19-pre2/include/asm-mips64/unistd.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-mips64/unistd.h	Mon Mar 11 14:13:30 2002
@@ -252,11 +252,12 @@
 #define __NR_Linux32_removexattr	(__NR_Linux32 + 233)
 #define __NR_Linux32_lremovexattr	(__NR_Linux32 + 234)
 #define __NR_Linux32_fremovexattr	(__NR_Linux32 + 235)
+#define __NR_Linux32_tkill		(__NR_Linux32 + 236)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux32_syscalls		235
+#define __NR_Linux32_syscalls		236
 
 /*
  * Linux 64-bit syscalls are in the range from 5000 to 5999.
@@ -491,11 +492,12 @@
 #define __NR_removexattr		(__NR_Linux + 226)
 #define __NR_lremovexattr		(__NR_Linux + 227)
 #define __NR_fremovexattr		(__NR_Linux + 228)
+#define __NR_tkill			(__NR_Linux + 229)
 
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls		228
+#define __NR_Linux_syscalls		229
 
 #ifndef _LANGUAGE_ASSEMBLY
 
diff -urN linux-2.4.19-pre2/include/asm-parisc/ide.h linux-2.4.19-pre3/include/asm-parisc/ide.h
--- linux-2.4.19-pre2/include/asm-parisc/ide.h	Tue Dec  5 12:29:39 2000
+++ linux-2.4.19-pre3/include/asm-parisc/ide.h	Mon Mar 11 14:13:30 2002
@@ -90,7 +90,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-parisc/pgalloc.h linux-2.4.19-pre3/include/asm-parisc/pgalloc.h
--- linux-2.4.19-pre2/include/asm-parisc/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux-2.4.19-pre3/include/asm-parisc/pgalloc.h	Mon Mar 11 14:13:30 2002
@@ -106,6 +106,9 @@
 #define flush_icache_range(start, end) \
         __flush_icache_range(start, end - start)
 
+#define flush_icache_user_range(vma, page, addr, len) \
+	flush_icache_page((vma), (page))
+
 #define flush_icache_page(vma, page) \
 	__flush_icache_range(page_address(page), PAGE_SIZE)
 
diff -urN linux-2.4.19-pre2/include/asm-parisc/siginfo.h linux-2.4.19-pre3/include/asm-parisc/siginfo.h
--- linux-2.4.19-pre2/include/asm-parisc/siginfo.h	Tue Dec  5 12:29:39 2000
+++ linux-2.4.19-pre3/include/asm-parisc/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-parisc/unistd.h linux-2.4.19-pre3/include/asm-parisc/unistd.h
--- linux-2.4.19-pre2/include/asm-parisc/unistd.h	Tue Dec  5 12:29:39 2000
+++ linux-2.4.19-pre3/include/asm-parisc/unistd.h	Mon Mar 11 14:13:30 2002
@@ -689,8 +689,10 @@
 
 #define __NR_getpmsg            (__NR_Linux + 196)      /* some people actually want streams */
 #define __NR_putpmsg            (__NR_Linux + 197)      /* some people actually want streams */
+#define __NR_gettid             (__NR_Linux + 198)
+#define __NR_tkill              (__NR_Linux + 199)
 
-#define __NR_Linux_syscalls     197
+#define __NR_Linux_syscalls     199
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
diff -urN linux-2.4.19-pre2/include/asm-ppc/ide.h linux-2.4.19-pre3/include/asm-ppc/ide.h
--- linux-2.4.19-pre2/include/asm-ppc/ide.h	Mon Oct  8 11:40:13 2001
+++ linux-2.4.19-pre3/include/asm-ppc/ide.h	Mon Mar 11 14:13:30 2002
@@ -129,6 +129,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
+
 #if !defined(ide_request_irq)
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #endif
diff -urN linux-2.4.19-pre2/include/asm-ppc/page.h linux-2.4.19-pre3/include/asm-ppc/page.h
--- linux-2.4.19-pre2/include/asm-ppc/page.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-ppc/page.h	Mon Mar 11 14:13:30 2002
@@ -83,8 +83,8 @@
 
 extern void clear_page(void *page);
 extern void copy_page(void *to, void *from);
-#define clear_user_page(page, vaddr)	clear_page(page)
-#define copy_user_page(to, from, vaddr)	copy_page(to, from)
+extern void clear_user_page(void *page, unsigned long vaddr);
+extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
 /* map phys->virtual and virtual->phys for RAM pages */
 static inline unsigned long ___pa(unsigned long v)
diff -urN linux-2.4.19-pre2/include/asm-ppc/pgtable.h linux-2.4.19-pre3/include/asm-ppc/pgtable.h
--- linux-2.4.19-pre2/include/asm-ppc/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-ppc/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -82,13 +82,14 @@
 #define flush_cache_mm(mm)		do { } while (0)
 #define flush_cache_range(mm, a, b)	do { } while (0)
 #define flush_cache_page(vma, p)	do { } while (0)
-#define flush_icache_page(vma, page)	do { } while (0)
+#define flush_page_to_ram(page)		do { } while (0)
 
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+		struct page *page, unsigned long addr, int len);
 extern void flush_icache_range(unsigned long, unsigned long);
-extern void __flush_page_to_ram(unsigned long page_va);
-extern void flush_page_to_ram(struct page *page);
-
-#define flush_dcache_page(page)			do { } while (0)
+extern void __flush_dcache_icache(void *page_va);
+extern void flush_dcache_page(struct page *page);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(unsigned long address);
@@ -441,10 +442,18 @@
 }
 
 /*
- * Writing a new value into the PTE doesn't disturb the state of the
- * _PAGE_HASHPTE bit, on those machines which use an MMU hash table.
+ * set_pte stores a linux PTE into the linux page table.
+ * On machines which use an MMU hash table we avoid changing the
+ * _PAGE_HASHPTE bit.
  */
-extern void set_pte(pte_t *ptep, pte_t pte);
+static inline void set_pte(pte_t *ptep, pte_t pte)
+{
+#if _PAGE_HASHPTE != 0
+	pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
+#else
+	*ptep = pte;
+#endif
+}
 
 static inline int ptep_test_and_clear_young(pte_t *ptep)
 {
diff -urN linux-2.4.19-pre2/include/asm-ppc/siginfo.h linux-2.4.19-pre3/include/asm-ppc/siginfo.h
--- linux-2.4.19-pre2/include/asm-ppc/siginfo.h	Mon May 21 15:02:06 2001
+++ linux-2.4.19-pre3/include/asm-ppc/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -108,6 +108,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-ppc/unistd.h linux-2.4.19-pre3/include/asm-ppc/unistd.h
--- linux-2.4.19-pre2/include/asm-ppc/unistd.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre3/include/asm-ppc/unistd.h	Mon Mar 11 14:13:30 2002
@@ -215,6 +215,7 @@
 #define __NR_madvise		205
 #define __NR_mincore		206
 #define __NR_gettid		207
+#define __NR_tkill		208
 
 #define __NR(n)	#n
 
diff -urN linux-2.4.19-pre2/include/asm-s390/atomic.h linux-2.4.19-pre3/include/asm-s390/atomic.h
--- linux-2.4.19-pre2/include/asm-s390/atomic.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre3/include/asm-s390/atomic.h	Mon Mar 11 14:13:30 2002
@@ -34,21 +34,8 @@
                              : "=&d" (old_val), "=&d" (new_val)		\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
-static __inline__ int atomic_read(atomic_t *v)
-{
-        int retval;
-        __asm__ __volatile__("bcr      15,0\n\t"
-                             "l        %0,%1"
-                             : "=d" (retval) : "m" (*v) );
-        return retval;
-}
-
-static __inline__ void atomic_set(atomic_t *v, int i)
-{
-        __asm__ __volatile__("st  %1,%0\n\t"
-                             "bcr 15,0"
-                             : "=m" (*v) : "d" (i) );
-}
+#define atomic_read(v)          ((v)->counter)
+#define atomic_set(v,i)         (((v)->counter) = (i))
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
diff -urN linux-2.4.19-pre2/include/asm-s390/bitops.h linux-2.4.19-pre3/include/asm-s390/bitops.h
--- linux-2.4.19-pre2/include/asm-s390/bitops.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre3/include/asm-s390/bitops.h	Mon Mar 11 14:13:30 2002
@@ -54,28 +54,29 @@
  */
 static __inline__ void set_bit_cs(int nr, volatile void * addr)
 {
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
-             "   lhi   2,1\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"       /* make OR mask */
+             "   sll   %3,0(%2)\n"       /* make OR mask */
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   or    1,2\n"          /* set bit */
-             "   cs    %0,1,0(%1)\n"
+             "0: lr    %2,%0\n"         /* CS loop starts here */
+             "   or    %2,%3\n"          /* set bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
+             : "cc", "memory" );
 }
 
 /*
@@ -83,30 +84,31 @@
  */
 static __inline__ void clear_bit_cs(int nr, volatile void * addr)
 {
-        static const int mask = -1;
+        static const int minusone = -1;
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
-             "   lhi   2,1\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"
-             "   x     2,%2\n"         /* make AND mask */
+             "   sll   %3,0(%2)\n"
+             "   x     %3,%4\n"        /* make AND mask */
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   nr    1,2\n"          /* clear bit */
-             "   cs    %0,1,0(%1)\n"
+             "0: lr    %2,%0\n"        /* CS loop starts here */
+             "   nr    %2,%3\n"        /* clear bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr) : "m" (mask)
-             : "cc", "memory", "1", "2" );
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask)
+             : "m" (minusone) : "cc", "memory" );
 }
 
 /*
@@ -114,28 +116,29 @@
  */
 static __inline__ void change_bit_cs(int nr, volatile void * addr)
 {
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
-             "   lhi   2,1\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"       /* make XR mask */
+             "   sll   %3,0(%2)\n"     /* make XR mask */
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   xr    1,2\n"          /* change bit */
-             "   cs    %0,1,0(%1)\n"
+             "0: lr    %2,%0\n"        /* CS loop starts here */
+             "   xr    %2,%3\n"        /* change bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr) : 
-             : "cc", "memory", "1", "2" );
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) : 
+             : "cc", "memory" );
 }
 
 /*
@@ -143,30 +146,31 @@
  */
 static __inline__ int test_and_set_bit_cs(int nr, volatile void * addr)
 {
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"       /* make OR mask */
+             "   sll   %3,0(%2)\n"     /* make OR mask */
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   or    1,2\n"          /* set bit */
-             "   cs    %0,1,0(%1)\n"
+             "0: lr    %2,%0\n"        /* CS loop starts here */
+             "   or    %2,%3\n"        /* set bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
-        return nr;
+             "   nr    %0,%3\n"        /* isolate old bit */
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
+             : "cc", "memory" );
+        return nr != 0;
 }
 
 /*
@@ -174,32 +178,33 @@
  */
 static __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr)
 {
-        static const int mask = -1;
+        static const int minusone = -1;
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"
-             "   x     2,%2\n"         /* make AND mask */
+             "   sll   %3,0(%2)\n"
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   nr    1,2\n"          /* clear bit */
-             "   cs    %0,1,0(%1)\n"
+             "   x     %3,%4\n"        /* make AND mask */
+             "0: lr    %2,%0\n"        /* CS loop starts here */
+             "   nr    %2,%3\n"        /* clear bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b\n"
-             "   x     2,%2\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) : "m" (mask)
-             : "cc", "memory", "1", "2" );
+             "   x     %3,%4\n"
+             "   nr    %0,%3\n"         /* isolate old bit */
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask)
+             : "m" (minusone) : "cc", "memory" );
         return nr;
 }
 
@@ -208,30 +213,31 @@
  */
 static __inline__ int test_and_change_bit_cs(int nr, volatile void * addr)
 {
+	unsigned long bits, mask;
         __asm__ __volatile__(
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+             "   lhi   %2,3\n"         /* CS must be aligned on 4 byte b. */
+             "   nr    %2,%1\n"        /* isolate last 2 bits of address */
+             "   xr    %1,%2\n"        /* make addr % 4 == 0 */
+             "   sll   %2,3\n"
+             "   ar    %0,%2\n"        /* add alignement to bitnr */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
+             "   lhi   %2,31\n"
+             "   nr    %2,%0\n"        /* make shift value */
+             "   xr    %0,%2\n"
              "   srl   %0,3\n"
+             "   lhi   %3,1\n"
              "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"       /* make OR mask */
+             "   sll   %3,0(%2)\n"     /* make OR mask */
              "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   xr    1,2\n"          /* change bit */
-             "   cs    %0,1,0(%1)\n"
+             "0: lr    %2,%0\n"        /* CS loop starts here */
+             "   xr    %2,%3\n"        /* change bit */
+             "   cs    %0,%2,0(%1)\n"
              "   jl    0b\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
-        return nr;
+             "   nr    %0,%3\n"        /* isolate old bit */
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
+             : "cc", "memory" );
+        return nr != 0;
 }
 #endif /* CONFIG_SMP */
 
@@ -240,17 +246,18 @@
  */
 static __inline__ void __set_bit(int nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   oc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lhi   %1,24\n"
+             "   lhi   %0,7\n"
+             "   xr    %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   oc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -319,17 +326,18 @@
 static __inline__ void 
 __clear_bit(int nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   nc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lhi   %1,24\n"
+             "   lhi   %0,7\n"
+             "   xr    %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   nc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_ni_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -397,17 +405,18 @@
  */
 static __inline__ void __change_bit(int nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   xc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lhi   %1,24\n"
+             "   lhi   %0,7\n"
+             "   xr    %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   xc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -475,24 +484,22 @@
  */
 static __inline__ int test_and_set_bit_simple(int nr, volatile void * addr)
 {
-        static const int mask = 1;
+	unsigned long reg1, reg2;
         int oldbit;
         __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   oc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_oi_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+             "   lhi   %1,24\n"
+             "   lhi   %2,7\n"
+             "   xr    %1,%3\n"
+             "   nr    %2,%3\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   oc    0(1,%1),0(%2)"
+             : "=d&" (oldbit), "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
+        return oldbit & 1;
 }
 #define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
 
@@ -501,25 +508,23 @@
  */
 static __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr)
 {
-        static const int mask = 1;
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   nc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_ni_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+             "   lhi   %1,24\n"
+             "   lhi   %2,7\n"
+             "   xr    %1,%3\n"
+             "   nr    %2,%3\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   nc    0(1,%1),0(%2)"
+             : "=d&" (oldbit), "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_ni_bitmap) : "cc", "memory" );
+        return oldbit & 1;
 }
 #define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
 
@@ -528,25 +533,23 @@
  */
 static __inline__ int test_and_change_bit_simple(int nr, volatile void * addr)
 {
-        static const int mask = 1;
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   xc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_oi_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+             "   lhi   %1,24\n"
+             "   lhi   %2,7\n"
+             "   xr    %1,%3\n"
+             "   nr    %2,%1\n"
+             "   srl   %1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   xc    0(1,%1),0(%2)"
+             : "=d&" (oldbit), "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
+        return oldbit & 1;
 }
 #define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
 
@@ -573,22 +576,20 @@
 
 static __inline__ int __test_bit(int nr, volatile void * addr)
 {
-        static const int mask = 1;
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%1\n"
-             "   nr    1,%1\n"
-             "   srl   2,3\n"
-             "   ic    %0,0(2,%2)\n"
-             "   srl   %0,0(1)\n"
-             "   n     %0,%3"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "m" (mask)
-             : "cc", "1", "2" );
-        return oldbit;
+             "   lhi   %2,24\n"
+             "   lhi   %1,7\n"
+             "   xr    %2,%3\n"
+             "   nr    %1,%3\n"
+             "   srl   %2,3\n"
+             "   ic    %0,0(%2,%4)\n"
+             "   srl   %0,0(%1)"
+             : "=d&" (oldbit), "=&a" (reg1), "=&a" (reg2)
+             : "r" (nr), "a" (addr) : "cc" );
+        return oldbit & 1;
 }
 
 static __inline__ int __constant_test_bit(int nr, volatile void * addr) {
@@ -605,48 +606,46 @@
  */
 static __inline__ int find_first_zero_bit(void * addr, unsigned size)
 {
-        static const int mask = 0xffL;
+	unsigned long cmp, count;
         int res;
 
         if (!size)
                 return 0;
-        __asm__("   lhi  0,-1\n"
-                "   lr   1,%1\n"
-                "   ahi  1,31\n"
-                "   srl  1,5\n"
-                "   sr   2,2\n"
-                "0: c    0,0(2,%2)\n"
+        __asm__("   lhi  %1,-1\n"
+                "   lr   %2,%3\n"
+                "   slr  %0,%0\n"
+                "   ahi  %2,31\n"
+                "   srl  %2,5\n"
+                "0: c    %1,0(%0,%4)\n"
                 "   jne  1f\n"
-                "   ahi  2,4\n"
-                "   brct 1,0b\n"
-                "   lr   2,%1\n"
+                "   ahi  %0,4\n"
+                "   brct %2,0b\n"
+                "   lr   %0,%3\n"
                 "   j    4f\n"
-                "1: l    1,0(2,%2)\n"
-                "   sll  2,3\n"
-                "   tml  1,0xFFFF\n"
+                "1: l    %2,0(%0,%4)\n"
+                "   sll  %0,3\n"
+                "   lhi  %1,0xff\n"
+                "   tml  %2,0xffff\n"
                 "   jno  2f\n"
-                "   ahi  2,16\n"
-                "   srl  1,16\n"
-                "2: tml  1,0x00FF\n"
+                "   ahi  %0,16\n"
+                "   srl  %2,16\n"
+                "2: tml  %2,0x00ff\n"
                 "   jno  3f\n"
-                "   ahi  2,8\n"
-                "   srl  1,8\n"
-                "3: n    1,%3\n"
-                "   ic   1,0(1,%4)\n"
-                "   n    1,%3\n"
-                "   ar   2,1\n"
-                "4: lr   %0,2"
-                : "=d" (res) : "a" (size), "a" (addr),
-                  "m" (mask), "a" (&_zb_findmap)
-                : "cc", "0", "1", "2" );
+                "   ahi  %0,8\n"
+                "   srl  %2,8\n"
+                "3: nr   %2,%1\n"
+                "   ic   %2,0(%2,%5)\n"
+                "   alr  %0,%2\n"
+                "4:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+                : "a" (size), "a" (addr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
 static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
-        static const int mask = 0xffL;
         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
-        unsigned long bitvec;
+        unsigned long bitvec, reg;
         int set, bit = offset & 31, res;
 
         if (bit) {
@@ -654,23 +653,21 @@
                  * Look for zero in first word
                  */
                 bitvec = (*p) >> bit;
-                __asm__("   lr   1,%1\n"
-                        "   sr   %0,%0\n"
-                        "   tml  1,0xFFFF\n"
+                __asm__("   slr  %0,%0\n"
+                        "   lhi  %2,0xff\n"
+                        "   tml  %1,0xffff\n"
                         "   jno  0f\n"
                         "   ahi  %0,16\n"
-                        "   srl  1,16\n"
-                        "0: tml  1,0x00FF\n"
+                        "   srl  %1,16\n"
+                        "0: tml  %1,0x00ff\n"
                         "   jno  1f\n"
                         "   ahi  %0,8\n"
-                        "   srl  1,8\n"
-                        "1: n    1,%2\n"
-                        "   ic   1,0(1,%3)\n"
-                        "   n    1,%2\n"
-                        "   ar   %0,1"
-                        : "=d&" (set) : "d" (bitvec),
-                          "m" (mask), "a" (&_zb_findmap)
-                          : "cc", "1" );
+                        "   srl  %1,8\n"
+                        "1: nr   %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   alr  %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_zb_findmap) : "cc" );
                 if (set < (32 - bit))
                         return set + offset;
                 offset += 32 - bit;
@@ -689,27 +686,24 @@
  */
 static __inline__ unsigned long ffz(unsigned long word)
 {
-        static const int mask = 0xffL;
+	unsigned long reg;
         int result;
 
-        __asm__("   lr   1,%1\n"
-                "   sr   %0,%0\n"
-                "   tml  1,0xFFFF\n"
+        __asm__("   slr  %0,%0\n"
+                "   lhi  %2,0xff\n"
+                "   tml  %1,0xffff\n"
                 "   jno  0f\n"
                 "   ahi  %0,16\n"
-                "   srl  1,16\n"
-                "0: tml  1,0x00FF\n"
+                "   srl  %1,16\n"
+                "0: tml  %1,0x00ff\n"
                 "   jno  1f\n"
                 "   ahi  %0,8\n"
-                "   srl  1,8\n"
-                "1: n    1,%2\n"
-                "   ic   1,0(1,%3)\n"
-                "   n    1,%2\n"
-                "   ar   %0,1"
-                : "=d&" (result) : "d" (word), 
-                  "m" (mask), "a" (&_zb_findmap)
-                : "cc", "1" );
-
+                "   srl  %1,8\n"
+                "1: nr   %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   alr  %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_zb_findmap) : "cc" );
         return result;
 }
 
@@ -725,29 +719,28 @@
 
         if (x == 0)
           return 0;
-        __asm__("    lr   %%r1,%1\n"
-                "    sr   %0,%0\n"
-                "    tml  %%r1,0xFFFF\n"
+        __asm__("    slr  %0,%0\n"
+                "    tml  %1,0xffff\n"
                 "    jnz  0f\n"
                 "    ahi  %0,16\n"
-                "    srl  %%r1,16\n"
-                "0:  tml  %%r1,0x00FF\n"
+                "    srl  %1,16\n"
+                "0:  tml  %1,0x00ff\n"
                 "    jnz  1f\n"
                 "    ahi  %0,8\n"
-                "    srl  %%r1,8\n"
-                "1:  tml  %%r1,0x000F\n"
+                "    srl  %1,8\n"
+                "1:  tml  %1,0x000f\n"
                 "    jnz  2f\n"
                 "    ahi  %0,4\n"
-                "    srl  %%r1,4\n"
-                "2:  tml  %%r1,0x0003\n"
+                "    srl  %1,4\n"
+                "2:  tml  %1,0x0003\n"
                 "    jnz  3f\n"
                 "    ahi  %0,2\n"
-                "    srl  %%r1,2\n"
-                "3:  tml  %%r1,0x0001\n"
+                "    srl  %1,2\n"
+                "3:  tml  %1,0x0001\n"
                 "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
-                : "=&d" (r) : "d" (x) : "cc", "1" );
+                : "=&d" (r), "+d" (x) : : "cc" );
         return r+1;
 }
 
@@ -778,40 +771,40 @@
 #define ext2_test_bit(nr, addr)      test_bit((nr)^24, addr)
 static __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
 {
+	unsigned long cmp, count;
         int res;
 
         if (!size)
                 return 0;
-        __asm__("   lhi  0,-1\n"
-                "   lr   1,%1\n"
-                "   ahi  1,31\n"
-                "   srl  1,5\n"
-                "   sr   2,2\n"
-                "0: c    0,0(2,%2)\n"
+        __asm__("   lhi  %1,-1\n"
+                "   lr   %2,%3\n"
+                "   ahi  %2,31\n"
+                "   srl  %2,5\n"
+                "   slr  %0,%0\n"
+                "0: cl   %1,0(%0,%4)\n"
                 "   jne  1f\n"
-                "   ahi  2,4\n"
-                "   brct 1,0b\n"
-                "   lr   2,%1\n"
+                "   ahi  %0,4\n"
+                "   brct %2,0b\n"
+                "   lr   %0,%3\n"
                 "   j    4f\n"
-                "1: l    1,0(2,%2)\n"
-                "   sll  2,3\n"
-                "   lhi  0,0xff\n"
-                "   ahi  2,24\n"
-                "   tmh  1,0xFFFF\n"
+                "1: l    %2,0(%0,%4)\n"
+                "   sll  %0,3\n"
+                "   ahi  %0,24\n"
+                "   lhi  %1,0xff\n"
+                "   tmh  %2,0xffff\n"
                 "   jo   2f\n"
-                "   ahi  2,-16\n"
-                "   srl  1,16\n"
-                "2: tml  1,0xFF00\n"
+                "   ahi  %0,-16\n"
+                "   srl  %2,16\n"
+                "2: tml  %2,0xff00\n"
                 "   jo   3f\n"
-                "   ahi  2,-8\n"
-                "   srl  1,8\n"
-                "3: nr   1,0\n"
-                "   ic   1,0(1,%3)\n"
-                "   ar   2,1\n"
-                "4: lr   %0,2"
-                : "=d" (res) : "a" (size), "a" (vaddr),
-                  "a" (&_zb_findmap)
-                  : "cc", "0", "1", "2" );
+                "   ahi  %0,-8\n"
+                "   srl  %2,8\n"
+                "3: nr   %2,%1\n"
+                "   ic   %2,0(%2,%5)\n"
+                "   alr  %0,%2\n"
+                "4:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+                : "a" (size), "a" (vaddr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
@@ -820,7 +813,7 @@
 {
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 5);
-        unsigned long word;
+        unsigned long word, reg;
         int bit = offset & 31UL, res;
 
         if (offset >= size)
@@ -835,21 +828,20 @@
 		word >>= bit;
                 res = bit;
                 /* Look for zero in first longword */
-                __asm__("   lhi  0,0xff\n"
+                __asm__("   lhi  %2,0xff\n"
                         "   tml  %1,0xffff\n"
-                	"   jno   0f\n"
+                	"   jno  0f\n"
                 	"   ahi  %0,16\n"
                 	"   srl  %1,16\n"
                 	"0: tml  %1,0x00ff\n"
                 	"   jno  1f\n"
                 	"   ahi  %0,8\n"
                 	"   srl  %1,8\n"
-                	"1: nr   %1,0\n"
-                	"   ic   %1,0(%1,%2)\n"
+                	"1: nr   %1,%2\n"
+                	"   ic   %1,0(%1,%3)\n"
                 	"   alr  %0,%1"
-                	: "+&d" (res), "+&a" (word)
-                  	: "a" (&_zb_findmap)
-                	: "cc", "0" );
+                	: "+&d" (res), "+&a" (word), "=&d" (reg)
+                  	: "a" (&_zb_findmap) : "cc" );
                 if (res < 32)
 			return (p - addr)*32 + res;
                 p++;
diff -urN linux-2.4.19-pre2/include/asm-s390/debug.h linux-2.4.19-pre3/include/asm-s390/debug.h
--- linux-2.4.19-pre2/include/asm-s390/debug.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390/debug.h	Mon Mar 11 14:13:30 2002
@@ -54,7 +54,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
+#define STCK(x)	asm volatile ("STCK 0(%0)" : : "a" (&(x)) : "memory", "cc")
 
 typedef struct __debug_entry debug_entry_t;
 
diff -urN linux-2.4.19-pre2/include/asm-s390/ebcdic.h linux-2.4.19-pre3/include/asm-s390/ebcdic.h
--- linux-2.4.19-pre2/include/asm-s390/ebcdic.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/include/asm-s390/ebcdic.h	Mon Mar 11 14:13:30 2002
@@ -24,7 +24,7 @@
 extern __inline__ 
 void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr)
 {
-	if (nr <= 0)
+	if (nr-- <= 0)
 		return;
         __asm__ __volatile__(
 		"   bras 1,1f\n"
@@ -34,7 +34,7 @@
 		"1: ahi  %1,-256\n"
 		"   jp   0b\n"
 		"   ex   %1,0(1)"
-                : "+&a" (addr), "+&a" (nr-1)
+                : "+&a" (addr), "+&a" (nr)
                 : "a" (codepage) : "cc", "memory", "1" );
 }
 
diff -urN linux-2.4.19-pre2/include/asm-s390/ide.h linux-2.4.19-pre3/include/asm-s390/ide.h
--- linux-2.4.19-pre2/include/asm-s390/ide.h	Fri May 12 11:41:44 2000
+++ linux-2.4.19-pre3/include/asm-s390/ide.h	Mon Mar 11 14:13:30 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -urN linux-2.4.19-pre2/include/asm-s390/irq.h linux-2.4.19-pre3/include/asm-s390/irq.h
--- linux-2.4.19-pre2/include/asm-s390/irq.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre3/include/asm-s390/irq.h	Mon Mar 11 14:13:30 2002
@@ -630,11 +630,6 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-                "    lr   1,%1\n"
-                "    msch 0(%2)\n"
-                "0:  ipm  %0\n"
-                "    srl  %0,28\n"
-                "1:\n"
 #else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
diff -urN linux-2.4.19-pre2/include/asm-s390/lowcore.h linux-2.4.19-pre3/include/asm-s390/lowcore.h
--- linux-2.4.19-pre2/include/asm-s390/lowcore.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/lowcore.h	Mon Mar 11 14:13:30 2002
@@ -185,12 +185,12 @@
 extern struct _lowcore *lowcore_ptr[];
 
 #ifndef CONFIG_SMP
-#define get_cpu_lowcore(cpu)    S390_lowcore
-#define safe_get_cpu_lowcore(cpu) S390_lowcore
+#define get_cpu_lowcore(cpu)      (&S390_lowcore)
+#define safe_get_cpu_lowcore(cpu) (&S390_lowcore)
 #else
-#define get_cpu_lowcore(cpu)    (*lowcore_ptr[cpu])
+#define get_cpu_lowcore(cpu)      (lowcore_ptr[(cpu)])
 #define safe_get_cpu_lowcore(cpu) \
-        ((cpu)==smp_processor_id() ? S390_lowcore:(*lowcore_ptr[(cpu)]))
+        ((cpu) == smp_processor_id() ? &S390_lowcore : lowcore_ptr[(cpu)])
 #endif
 #endif /* __ASSEMBLY__ */
 
diff -urN linux-2.4.19-pre2/include/asm-s390/pgtable.h linux-2.4.19-pre3/include/asm-s390/pgtable.h
--- linux-2.4.19-pre2/include/asm-s390/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-s390/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -42,6 +42,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)          do { } while (0)
 #define flush_icache_page(vma,pg)               do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
diff -urN linux-2.4.19-pre2/include/asm-s390/processor.h linux-2.4.19-pre3/include/asm-s390/processor.h
--- linux-2.4.19-pre2/include/asm-s390/processor.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/processor.h	Mon Mar 11 14:13:30 2002
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
+#ifdef __KERNEL__
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -64,8 +65,7 @@
 #define THREAD_SIZE (2*PAGE_SIZE)
 
 typedef struct {
-        unsigned long seg;
-        unsigned long acc4;
+        unsigned long ar4;
 } mm_segment_t;
 
 /* if you change the thread_struct structure, you must
@@ -82,8 +82,6 @@
         __u32   error_code;            /* error-code of last prog-excep.   */
         __u32   prot_addr;             /* address of protection-excep.     */
         __u32   trap_no;
-        /* perform syscall argument validation (get/set_fs) */
-        mm_segment_t fs;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
 	/* Used to give failing instruction back to user for ieee exceptions */
 	addr_t  ieee_instruction_pointer; 
@@ -99,7 +97,6 @@
                     sizeof(init_stack) + (__u32) &init_stack,     \
               (__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
                      0,0,0,                                       \
-                     (mm_segment_t) { 0,1},                       \
                      (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
                      0, 0                                         \
 }
@@ -138,8 +135,8 @@
 }
 
 unsigned long get_wchan(struct task_struct *p);
-#define __KSTK_PTREGS(tsk) \
-	((struct pt_regs *)((unsigned long) tsk+THREAD_SIZE) - 1)
+#define __KSTK_PTREGS(tsk) ((struct pt_regs *) \
+	(((unsigned long) tsk + THREAD_SIZE - sizeof(struct pt_regs)) & -8L))
 #define KSTK_EIP(tsk)	(__KSTK_PTREGS(tsk)->psw.addr)
 #define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
@@ -171,6 +168,46 @@
 #define PSW_PROBLEM_STATE       0x00010000UL
 
 /*
+ * Set PSW mask to specified value, while leaving the
+ * PSW addr pointing to the next instruction.
+ */
+
+static inline void __load_psw_mask (unsigned long mask)
+{
+	unsigned long addr;
+
+	psw_t psw;
+	psw.mask = mask;
+
+	asm volatile (
+		"    basr %0,0\n"
+		"0:  ahi  %0,1f-0b\n"
+		"    st   %0,4(%1)\n"
+		"    lpsw 0(%1)\n"
+		"1:"
+		: "=&d" (addr) : "a" (&psw) : "memory", "cc" );
+}
+ 
+/*
+ * Function to stop a processor until an interruption occured
+ */
+static inline void enabled_wait(void)
+{
+	unsigned long reg;
+	psw_t wait_psw;
+
+	wait_psw.mask = 0x070e0000;
+	asm volatile (
+		"    basr %0,0\n"
+		"0:  la   %0,1f-0b(%0)\n"
+		"    st   %0,4(%1)\n"
+		"    oi   4(%1),0x80\n"
+		"    lpsw 0(%1)\n"
+		"1:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+/*
  * Function to drop a processor into disabled wait state
  */
 
@@ -206,4 +243,6 @@
                       : : "a" (dw_psw), "a" (&ctl_buf) : "cc" );
 }
 
+#endif
+
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -urN linux-2.4.19-pre2/include/asm-s390/ptrace.h linux-2.4.19-pre3/include/asm-s390/ptrace.h
--- linux-2.4.19-pre2/include/asm-s390/ptrace.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/ptrace.h	Mon Mar 11 14:13:30 2002
@@ -174,7 +174,6 @@
 	__u32 acrs[NUM_ACRS];
 	__u32 orig_gpr2;
 	__u32 trap;
-        __u32 old_ilc;
 };
 
 /*
diff -urN linux-2.4.19-pre2/include/asm-s390/rwsem.h linux-2.4.19-pre3/include/asm-s390/rwsem.h
--- linux-2.4.19-pre2/include/asm-s390/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/include/asm-s390/rwsem.h	Mon Mar 11 14:13:30 2002
@@ -0,0 +1,209 @@
+#ifndef _S390_RWSEM_H
+#define _S390_RWSEM_H
+
+/*
+ *  include/asm-s390/rwsem.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
+ */
+
+/*
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed long		count;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+};
+
+#define RWSEM_UNLOCKED_VALUE	0x00000000
+#define RWSEM_ACTIVE_BIAS	0x00000001
+#define RWSEM_ACTIVE_MASK	0x0000ffff
+#define RWSEM_WAITING_BIAS	(-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+/*
+ * initialisation
+ */
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (old < 0)
+		rwsem_down_read_failed(sem);
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   a    %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (old != 0)
+		rwsem_down_write_failed(sem);
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   a    %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ar   %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ar   %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+	return new;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _S390_RWSEM_H */
diff -urN linux-2.4.19-pre2/include/asm-s390/siginfo.h linux-2.4.19-pre3/include/asm-s390/siginfo.h
--- linux-2.4.19-pre2/include/asm-s390/siginfo.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -115,6 +115,7 @@
 #define SI_MESGQ	-3	/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-s390/sigp.h linux-2.4.19-pre3/include/asm-s390/sigp.h
--- linux-2.4.19-pre2/include/asm-s390/sigp.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390/sigp.h	Mon Mar 11 14:13:30 2002
@@ -129,6 +129,6 @@
    return ccode;
 }
 
-#endif __SIGP__
+#endif /* __SIGP__ */
 
 
diff -urN linux-2.4.19-pre2/include/asm-s390/spinlock.h linux-2.4.19-pre3/include/asm-s390/spinlock.h
--- linux-2.4.19-pre2/include/asm-s390/spinlock.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390/spinlock.h	Mon Mar 11 14:13:30 2002
@@ -29,22 +29,24 @@
 
 extern inline void spin_lock(spinlock_t *lp)
 {
-        __asm__ __volatile("    bras  1,1f\n"
+	unsigned int reg1, reg2;
+        __asm__ __volatile("    bras  %0,1f\n"
                            "0:  diag  0,0,68\n"
-                           "1:  slr   0,0\n"
-                           "    cs    0,1,0(%0)\n"
+                           "1:  slr   %1,%1\n"
+                           "    cs    %1,%0,0(%2)\n"
                            "    jl    0b\n"
-                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
+                           : "=&d" (reg1), "=&d" (reg2)
+			   : "a" (&lp->lock) : "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
 {
-	unsigned long result;
+	unsigned long result, reg;
 	__asm__ __volatile("    slr   %0,%0\n"
-			   "    basr  1,0\n"
-			   "0:  cs    %0,1,0(%1)"
-			   : "=&d" (result)
-			   : "a" (&lp->lock) : "1", "cc", "memory" );
+			   "    basr  %1,0\n"
+			   "0:  cs    %0,%1,0(%2)"
+			   : "=&d" (result), "=&d" (reg)
+			   : "a" (&lp->lock) : "cc", "memory" );
 	return !result;
 }
 
diff -urN linux-2.4.19-pre2/include/asm-s390/system.h linux-2.4.19-pre3/include/asm-s390/system.h
--- linux-2.4.19-pre2/include/asm-s390/system.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre3/include/asm-s390/system.h	Mon Mar 11 14:13:30 2002
@@ -12,6 +12,7 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #ifdef __KERNEL__
 #include <asm/lowcore.h>
 #endif
@@ -23,7 +24,7 @@
                 break;                                                       \
 	save_fp_regs1(&prev->thread.fp_regs);                                \
 	restore_fp_regs1(&next->thread.fp_regs);              		     \
-	last = resume(&prev->thread,&next->thread);                          \
+	last = resume(prev,next);					     \
 } while (0)
 
 struct task_struct;
@@ -97,8 +98,6 @@
                                 : "+d&" (x) : "a" (ptr)
                                 : "memory", "cc", "0" );
                         break;
-               default:
-                        abort();
         }
         return x;
 }
@@ -132,24 +131,24 @@
 #define __sti() ({ \
         __u8 dummy; \
         __asm__ __volatile__ ( \
-                "stosm %0,0x03" : "=m" (dummy) : : "memory"); \
+                "stosm 0(%0),0x03" : : "a" (&dummy) : "memory"); \
         })
 
 #define __cli() ({ \
         __u32 flags; \
         __asm__ __volatile__ ( \
-                "stnsm %0,0xFC" : "=m" (flags) : : "memory"); \
+                "stnsm 0(%0),0xFC" : : "a" (&flags) : "memory"); \
         flags; \
         })
 
 #define __save_flags(x) \
-        __asm__ __volatile__("stosm %0,0" : "=m" (x) : : "memory")
+        __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory")
 
 #define __restore_flags(x) \
-        __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
+        __asm__ __volatile__("ssm   0(%0)" : : "a" (&x) : "memory")
 
 #define __load_psw(psw) \
-	__asm__ __volatile__("lpsw %0" : : "m" (psw) : "cc" );
+	__asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
@@ -244,7 +243,7 @@
 #endif
 
 #ifdef __KERNEL__
-extern struct task_struct *resume(void *,void *);
+extern struct task_struct *resume(void *, void *);
 
 extern int save_fp_regs1(s390_fp_regs *fpregs);
 extern void save_fp_regs(s390_fp_regs *fpregs);
diff -urN linux-2.4.19-pre2/include/asm-s390/timex.h linux-2.4.19-pre3/include/asm-s390/timex.h
--- linux-2.4.19-pre2/include/asm-s390/timex.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/timex.h	Mon Mar 11 14:13:30 2002
@@ -25,8 +25,16 @@
 {
 	cycles_t cycles;
 
-	__asm__("stck  %0" : "=m" (cycles) : : "cc");
+	__asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
 	return cycles >> 2;
 }
 
+static inline unsigned long long get_clock (void)
+{
+	unsigned long long clk;
+
+	__asm__("stck 0(%0)" : : "a" (&(clk)) : "memory", "cc");
+	return clk;
+}
+
 #endif
diff -urN linux-2.4.19-pre2/include/asm-s390/uaccess.h linux-2.4.19-pre3/include/asm-s390/uaccess.h
--- linux-2.4.19-pre2/include/asm-s390/uaccess.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390/uaccess.h	Mon Mar 11 14:13:30 2002
@@ -28,21 +28,21 @@
  * For historical reasons, these macros are grossly misnamed.
  */
 
-#define MAKE_MM_SEG(s,a)  ((mm_segment_t) { (s),(a) })
+#define MAKE_MM_SEG(a)  ((mm_segment_t) { (a) })
 
 
-#define KERNEL_DS       MAKE_MM_SEG(0x7FFFFFFF,0)
-#define USER_DS         MAKE_MM_SEG(PAGE_OFFSET,1)
+#define KERNEL_DS       MAKE_MM_SEG(0)
+#define USER_DS         MAKE_MM_SEG(1)
 
 #define get_ds()        (KERNEL_DS)
-#define get_fs()        (current->thread.fs)
-#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" (x.acc4)); \
-                         current->thread.fs = (x);})
+#define get_fs()        (current->addr_limit)
+#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4)); \
+                         current->addr_limit = (x);})
 
-#define segment_eq(a,b) ((a).acc4 == (b).acc4)
+#define segment_eq(a,b) ((a).ar4 == (b).ar4)
 
 
-#define __access_ok(addr,size) ((((long) addr + size)&0x7FFFFFFFL) < current->addr_limit.seg)
+#define __access_ok(addr,size) (1)
 
 #define access_ok(type,addr,size) __access_ok(addr,size)
 
diff -urN linux-2.4.19-pre2/include/asm-s390/unistd.h linux-2.4.19-pre3/include/asm-s390/unistd.h
--- linux-2.4.19-pre2/include/asm-s390/unistd.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390/unistd.h	Mon Mar 11 14:13:30 2002
@@ -211,6 +211,8 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64		220
+#define __NR_gettid		226
+#define __NR_tkill		227
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
diff -urN linux-2.4.19-pre2/include/asm-s390x/atomic.h linux-2.4.19-pre3/include/asm-s390x/atomic.h
--- linux-2.4.19-pre2/include/asm-s390x/atomic.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre3/include/asm-s390x/atomic.h	Mon Mar 11 14:13:30 2002
@@ -34,21 +34,8 @@
                              : "=&d" (old_val), "=&d" (new_val)		\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
-static __inline__ int atomic_read(atomic_t *v)
-{
-        int retval;
-        __asm__ __volatile__("bcr      15,0\n\t"
-                             "l        %0,%1"
-                             : "=d" (retval) : "m" (*v) );
-        return retval;
-}
-
-static __inline__ void atomic_set(atomic_t *v, int i)
-{
-        __asm__ __volatile__("st  %1,%0\n\t"
-                             "bcr 15,0"
-                             : "=m" (*v) : "d" (i) );
-}
+#define atomic_read(v)          ((v)->counter)
+#define atomic_set(v,i)         (((v)->counter) = (i))
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
diff -urN linux-2.4.19-pre2/include/asm-s390x/bitops.h linux-2.4.19-pre3/include/asm-s390x/bitops.h
--- linux-2.4.19-pre2/include/asm-s390x/bitops.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/include/asm-s390x/bitops.h	Mon Mar 11 14:13:30 2002
@@ -79,7 +79,7 @@
              "   ogr   %2,%3\n"        /* set bit */
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
              : "cc", "memory" );
 }
 
@@ -110,7 +110,7 @@
              "   ngr   %2,%3\n"        /* clear bit */
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
              : "cc", "memory" );
 }
 
@@ -140,7 +140,7 @@
              "   xgr   %2,%3\n"        /* change bit */
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) : 
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) : 
              : "cc", "memory" );
 }
 
@@ -172,7 +172,7 @@
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b\n"
              "   ngr   %0,%3\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
              : "cc", "memory" );
         return nr != 0;
 }
@@ -205,7 +205,7 @@
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b\n"
              "   xgr   %0,%2\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
              : "cc", "memory" );
         return nr != 0;
 }
@@ -238,7 +238,7 @@
              "   csg   %0,%2,0(%1)\n"
              "   jl    0b\n"
              "   ngr   %0,%3\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
+             : "+a" (nr), "+a" (addr), "=&a" (bits), "=&d" (mask) :
              : "cc", "memory" );
         return nr != 0;
 }
@@ -249,17 +249,18 @@
  */
 static __inline__ void __set_bit(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   oc    0(1,2),0(1)"
-             :  : "a" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %0,7\n"
+             "   xgr   %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   oc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+             : "a" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -328,17 +329,18 @@
 static __inline__ void 
 __clear_bit(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   nc    0(1,2),0(1)"
-             :  : "d" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %0,7\n"
+             "   xgr   %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   nc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr), "a" (&_ni_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -406,17 +408,18 @@
  */
 static __inline__ void __change_bit(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   xc    0(1,2),0(1)"
-             :  : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %0,7\n"
+             "   xgr   %1,%2\n"
+             "   nr    %0,%2\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%3)\n"
+             "   la    %0,0(%0,%4)\n"
+             "   xc    0(1,%1),0(%0)"
+             : "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
 }
 
 static __inline__ void 
@@ -485,20 +488,21 @@
 static __inline__ int
 test_and_set_bit_simple(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         int oldbit;
         __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   oc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %2,7\n"
+             "   xgr   %1,%3\n"
+             "   nr    %2,%3\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   oc    0(1,%1),0(%2)"
+             : "=&d" (oldbit), "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
         return oldbit & 1;
 }
 #define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
@@ -509,21 +513,22 @@
 static __inline__ int
 test_and_clear_bit_simple(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   nc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %2,7\n"
+             "   xgr   %1,%3\n"
+             "   nr    %2,%3\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   nc    0(1,%1),0(%2)"
+             : "=&d" (oldbit), "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr), "a" (&_ni_bitmap) : "cc", "memory" );
         return oldbit & 1;
 }
 #define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
@@ -534,21 +539,22 @@
 static __inline__ int
 test_and_change_bit_simple(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   xc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
+             "   lghi  %1,56\n"
+             "   lghi  %2,7\n"
+             "   xgr   %1,%3\n"
+             "   nr    %2,%3\n"
+             "   srlg  %1,%1,3\n"
+             "   la    %1,0(%1,%4)\n"
+             "   ic    %0,0(%1)\n"
+             "   srl   %0,0(%2)\n"
+             "   la    %2,0(%2,%5)\n"
+             "   xc    0(1,%1),0(%2)"
+             : "=&d" (oldbit), "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr), "a" (&_oi_bitmap) : "cc", "memory" );
         return oldbit & 1;
 }
 #define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
@@ -576,18 +582,19 @@
 
 static __inline__ int __test_bit(unsigned long nr, volatile void * addr)
 {
+	unsigned long reg1, reg2;
         int oldbit;
 
         __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%1\n"
-             "   nr    1,%1\n"
-             "   srlg  2,2,3\n"
-             "   ic    %0,0(2,%2)\n"
-             "   srl   %0,0(1)\n"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr)
-             : "cc", "1", "2" );
+             "   lghi  %2,56\n"
+             "   lghi  %1,7\n"
+             "   xgr   %2,%3\n"
+             "   nr    %1,%3\n"
+             "   srlg  %2,%2,3\n"
+             "   ic    %0,0(%2,%4)\n"
+             "   srl   %0,0(%1)\n"
+             : "=&d" (oldbit), "=&a" (reg1), "=&a" (reg2)
+	     : "d" (nr), "a" (addr) : "cc" );
         return oldbit & 1;
 }
 
@@ -607,42 +614,42 @@
 static __inline__ unsigned long
 find_first_zero_bit(void * addr, unsigned long size)
 {
-        unsigned long res;
+        unsigned long res, cmp, count;
 
         if (!size)
                 return 0;
-        __asm__("   lghi  0,-1\n"
-                "   lgr   1,%1\n"
+        __asm__("   lghi  %1,-1\n"
+                "   lgr   %2,%3\n"
                 "   slgr  %0,%0\n"
-                "   aghi  1,63\n"
-                "   srlg  1,1,6\n"
-                "0: cg    0,0(%0,%2)\n"
+                "   aghi  %2,63\n"
+                "   srlg  %2,%2,6\n"
+                "0: cg    %1,0(%0,%4)\n"
                 "   jne   1f\n"
                 "   aghi  %0,8\n"
-                "   brct  1,0b\n"
-                "   lgr   %0,%1\n"
+                "   brct  %2,0b\n"
+                "   lgr   %0,%3\n"
                 "   j     5f\n"
-                "1: lg    1,0(%0,%2)\n"
+                "1: lg    %2,0(%0,%4)\n"
                 "   sllg  %0,%0,3\n"
-                "   clr   1,0\n"
+                "   clr   %2,%1\n"
 		"   jne   2f\n"
 		"   aghi  %0,32\n"
-                "   srlg  1,1,32\n"
-		"2: lghi  0,0xff\n"
-                "   tmll  1,0xffff\n"
+                "   srlg  %2,%2,32\n"
+		"2: lghi  %1,0xff\n"
+                "   tmll  %2,0xffff\n"
                 "   jno   3f\n"
                 "   aghi  %0,16\n"
-                "   srl   1,16\n"
-                "3: tmll  1,0x00ff\n"
+                "   srl   %2,16\n"
+                "3: tmll  %2,0x00ff\n"
                 "   jno   4f\n"
                 "   aghi  %0,8\n"
-                "   srl   1,8\n"
-                "4: ngr   1,0\n"
-                "   ic    1,0(1,%3)\n"
-                "   algr  %0,1\n"
+                "   srl   %2,8\n"
+                "4: ngr   %2,%1\n"
+                "   ic    %2,0(%2,%5)\n"
+                "   algr  %0,%2\n"
                 "5:"
-                : "=&a" (res) : "a" (size), "a" (addr), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+		: "a" (size), "a" (addr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
@@ -650,7 +657,7 @@
 find_next_zero_bit (void * addr, unsigned long size, unsigned long offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
-        unsigned long bitvec;
+        unsigned long bitvec, reg;
         unsigned long set, bit = offset & 63, res;
 
         if (bit) {
@@ -658,28 +665,26 @@
                  * Look for zero in first word
                  */
                 bitvec = (*p) >> bit;
-                __asm__("   lhi  0,-1\n"
-                        "   lgr  1,%1\n"
+                __asm__("   lhi  %2,-1\n"
                         "   slgr %0,%0\n"
-                        "   clr  1,0\n"
+                        "   clr  %1,%2\n"
                         "   jne  0f\n"
                         "   aghi %0,32\n"
-                        "   srlg 1,1,32\n"
-			"0: lghi 0,0xff\n"
-                        "   tmll 1,0xffff\n"
+                        "   srlg %1,%1,32\n"
+			"0: lghi %2,0xff\n"
+                        "   tmll %1,0xffff\n"
                         "   jno  1f\n"
                         "   aghi %0,16\n"
-                        "   srlg 1,1,16\n"
-                        "1: tmll 1,0x00ff\n"
+                        "   srlg %1,%1,16\n"
+                        "1: tmll %1,0x00ff\n"
                         "   jno  2f\n"
                         "   aghi %0,8\n"
-                        "   srlg 1,1,8\n"
-                        "2: ngr  1,0\n"
-                        "   ic   1,0(1,%2)\n"
-                        "   algr %0,1"
-                        : "=&d" (set) 
-                        : "d" (bitvec), "a" (&_zb_findmap)
-                        : "cc", "0", "1" );
+                        "   srlg %1,%1,8\n"
+                        "2: ngr  %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   algr %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_zb_findmap) : "cc" );
                 if (set < (64 - bit))
                         return set + offset;
                 offset += 64 - bit;
@@ -698,31 +703,29 @@
  */
 static __inline__ unsigned long ffz(unsigned long word)
 {
+	unsigned long reg;
         int result;
 
-        __asm__("   lhi  0,-1\n"
-                "   lgr  1,%1\n"
+        __asm__("   lhi  %2,-1\n"
                 "   slgr %0,%0\n"
-                "   clr  1,0\n"
+                "   clr  %1,%2\n"
                 "   jne  0f\n"
                 "   aghi %0,32\n"
-                "   srlg 1,1,32\n"
-                "0: lghi 0,0xff\n"
-                "   tmll 1,0xffff\n"
+                "   srlg %1,%1,32\n"
+                "0: lghi %2,0xff\n"
+                "   tmll %1,0xffff\n"
                 "   jno  1f\n"
                 "   aghi %0,16\n"
-                "   srlg 1,1,16\n"
-                "1: tmll 1,0x00ff\n"
+                "   srlg %1,%1,16\n"
+                "1: tmll %1,0x00ff\n"
                 "   jno  2f\n"
                 "   aghi %0,8\n"
-                "   srlg 1,1,8\n"
-                "2: ngr  1,0\n"
-                "   ic   1,0(1,%2)\n"
-                "   algr %0,1"
-                : "=&d" (result)
-                : "d" (word), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
-
+                "   srlg %1,%1,8\n"
+                "2: ngr  %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   algr %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_zb_findmap) : "cc" );
         return result;
 }
 
@@ -738,29 +741,28 @@
 
         if (x == 0)
           return 0;
-        __asm__("    lr   1,%1\n"
-                "    slr  %0,%0\n"
-                "    tml  1,0xFFFF\n"
+        __asm__("    slr  %0,%0\n"
+                "    tml  %1,0xffff\n"
                 "    jnz  0f\n"
                 "    ahi  %0,16\n"
-                "    srl  1,16\n"
-                "0:  tml  1,0x00FF\n"
+                "    srl  %1,16\n"
+                "0:  tml  %1,0x00ff\n"
                 "    jnz  1f\n"
                 "    ahi  %0,8\n"
-                "    srl  1,8\n"
-                "1:  tml  1,0x000F\n"
+                "    srl  %1,8\n"
+                "1:  tml  %1,0x000f\n"
                 "    jnz  2f\n"
                 "    ahi  %0,4\n"
-                "    srl  1,4\n"
-                "2:  tml  1,0x0003\n"
+                "    srl  %1,4\n"
+                "2:  tml  %1,0x0003\n"
                 "    jnz  3f\n"
                 "    ahi  %0,2\n"
-                "    srl  1,2\n"
-                "3:  tml  1,0x0001\n"
+                "    srl  %1,2\n"
+                "3:  tml  %1,0x0001\n"
                 "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
-                : "=&d" (r) : "d" (x) : "cc", "1" );
+                : "=&d" (r), "+d" (x) : : "cc" );
         return r+1;
 }
 
@@ -792,42 +794,42 @@
 static __inline__ unsigned long
 ext2_find_first_zero_bit(void *vaddr, unsigned long size)
 {
-        unsigned long res;
+        unsigned long res, cmp, count;
 
         if (!size)
                 return 0;
-        __asm__("   lghi  0,-1\n"
-                "   lgr   1,%1\n"
-                "   aghi  1,63\n"
-                "   srlg  1,1,6\n"
+        __asm__("   lghi  %1,-1\n"
+                "   lgr   %2,%3\n"
+                "   aghi  %2,63\n"
+                "   srlg  %2,%2,6\n"
                 "   slgr  %0,%0\n"
-                "0: clg   0,0(%0,%2)\n"
+                "0: clg   %1,0(%0,%4)\n"
                 "   jne   1f\n"
                 "   aghi  %0,8\n"
-                "   brct  1,0b\n"
-                "   lgr   %0,%1\n"
+                "   brct  %2,0b\n"
+                "   lgr   %0,%3\n"
                 "   j     5f\n"
-                "1: cl    0,0(%0,%2)\n"
+                "1: cl    %1,0(%0,%4)\n"
 		"   jne   2f\n"
 		"   aghi  %0,4\n"
-		"2: l     1,0(%0,%2)\n"
+		"2: l     %2,0(%0,%4)\n"
                 "   sllg  %0,%0,3\n"
                 "   aghi  %0,24\n"
-                "   lghi  0,0xff\n"
-                "   tmlh  1,0xffff\n"
+                "   lghi  %1,0xff\n"
+                "   tmlh  %2,0xffff\n"
                 "   jo    3f\n"
                 "   aghi  %0,-16\n"
-                "   srl   1,16\n"
-                "3: tmll  1,0xff00\n"
+                "   srl   %2,16\n"
+                "3: tmll  %2,0xff00\n"
                 "   jo    4f\n"
                 "   aghi  %0,-8\n"
-                "   srl   1,8\n"
-                "4: ngr   1,0\n"
-                "   ic    1,0(1,%3)\n"
-                "   algr  %0,1\n"
+                "   srl   %2,8\n"
+                "4: ngr   %2,%1\n"
+                "   ic    %2,0(%2,%5)\n"
+                "   algr  %0,%2\n"
                 "5:"
-                : "=&a" (res) : "a" (size), "a" (vaddr), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+		: "a" (size), "a" (vaddr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
@@ -836,7 +838,7 @@
 {
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 6);
-        unsigned long word;
+        unsigned long word, reg;
         unsigned long bit = offset & 63UL, res;
 
         if (offset >= size)
@@ -848,30 +850,28 @@
                 word >>= bit;
                 res = bit;
                 /* Look for zero in first 8 byte word */
-                __asm__("   lgr  1,%1\n"
-                        "   lghi 0,0xff\n"
-			"   tmll 1,0xffff\n"
+                __asm__("   lghi %2,0xff\n"
+			"   tmll %1,0xffff\n"
 			"   jno  2f\n"
 			"   ahi  %0,16\n"
-			"   srlg 1,1,16\n"
-                	"0: tmll 1,0xffff\n"
+			"   srlg %1,%1,16\n"
+                	"0: tmll %1,0xffff\n"
                         "   jno  2f\n"
                         "   ahi  %0,16\n"
-                        "   srlg 1,1,16\n"
-                        "1: tmll 1,0xffff\n"
+                        "   srlg %1,%1,16\n"
+                        "1: tmll %1,0xffff\n"
                         "   jno  2f\n"
                         "   ahi  %0,16\n"
-                        "   srl  1,16\n"
-                        "2: tmll 1,0x00ff\n"
+                        "   srl  %1,16\n"
+                        "2: tmll %1,0x00ff\n"
                 	"   jno  3f\n"
                 	"   ahi  %0,8\n"
-                	"   srl  1,8\n"
-                	"3: ngr  1,0\n"
-                	"   ic   1,0(1,%2)\n"
-                	"   alr  %0,1"
-                	: "+&d" (res) 
-                  	: "d" (word), "a" (&_zb_findmap)
-                	: "cc", "0", "1" );
+                	"   srl  %1,8\n"
+                	"3: ngr  %1,%2\n"
+                	"   ic   %1,0(%1,%3)\n"
+                	"   alr  %0,%1"
+                	: "+&d" (res), "+a" (word), "=&d" (reg)
+                  	: "a" (&_zb_findmap) : "cc" );
                 if (res < 64)
 			return (p - addr)*64 + res;
                 p++;
diff -urN linux-2.4.19-pre2/include/asm-s390x/debug.h linux-2.4.19-pre3/include/asm-s390x/debug.h
--- linux-2.4.19-pre2/include/asm-s390x/debug.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390x/debug.h	Mon Mar 11 14:13:30 2002
@@ -54,7 +54,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
+#define STCK(x)	asm volatile ("STCK 0(%0)" : : "a" (&(x)) : "memory", "cc")
 
 typedef struct __debug_entry debug_entry_t;
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/ebcdic.h linux-2.4.19-pre3/include/asm-s390x/ebcdic.h
--- linux-2.4.19-pre2/include/asm-s390x/ebcdic.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.19-pre3/include/asm-s390x/ebcdic.h	Mon Mar 11 14:13:30 2002
@@ -24,7 +24,7 @@
 extern __inline__ void
 codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
 {
-	if (nr <= 0)
+	if (nr-- <= 0)
 		return;
         __asm__ __volatile__(
 		"   bras  1,1f\n"
@@ -34,7 +34,7 @@
 		"1: ahi   %1,-256\n"
 		"   jp    0b\n"
 		"   ex    %1,0(1)"
-		: "+&a" (addr), "+&a" (nr-1)
+		: "+&a" (addr), "+&a" (nr)
 		: "a" (codepage) : "cc", "memory", "1" );
 }
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/ide.h linux-2.4.19-pre3/include/asm-s390x/ide.h
--- linux-2.4.19-pre2/include/asm-s390x/ide.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.19-pre3/include/asm-s390x/ide.h	Mon Mar 11 14:13:30 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -urN linux-2.4.19-pre2/include/asm-s390x/irq.h linux-2.4.19-pre3/include/asm-s390x/irq.h
--- linux-2.4.19-pre2/include/asm-s390x/irq.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre3/include/asm-s390x/irq.h	Mon Mar 11 14:13:30 2002
@@ -630,11 +630,6 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-                "    lr   1,%1\n"
-                "    msch 0(%2)\n"
-                "0:  ipm  %0\n"
-                "    srl  %0,28\n"
-                "1:\n"
 #else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
diff -urN linux-2.4.19-pre2/include/asm-s390x/lowcore.h linux-2.4.19-pre3/include/asm-s390x/lowcore.h
--- linux-2.4.19-pre2/include/asm-s390x/lowcore.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390x/lowcore.h	Mon Mar 11 14:13:30 2002
@@ -62,7 +62,7 @@
 #define _SVC_PSW_MASK        0x0400000180000000
 #define _MCCK_PSW_MASK       0x0400000180000000
 #define _IO_PSW_MASK         0x0400000180000000
-#define _USER_PSW_MASK       0x0701C00180000000
+#define _USER_PSW_MASK       0x0705C00180000000
 #define _WAIT_PSW_MASK       0x0706000180000000
 #define _DW_PSW_MASK         0x0002000180000000
 
@@ -200,12 +200,12 @@
 extern struct _lowcore *lowcore_ptr[];
 
 #ifndef CONFIG_SMP
-#define get_cpu_lowcore(cpu)    S390_lowcore
-#define safe_get_cpu_lowcore(cpu) S390_lowcore
+#define get_cpu_lowcore(cpu)      (&S390_lowcore)
+#define safe_get_cpu_lowcore(cpu) (&S390_lowcore)
 #else
-#define get_cpu_lowcore(cpu)    (*lowcore_ptr[cpu])
+#define get_cpu_lowcore(cpu)      (lowcore_ptr[(cpu)])
 #define safe_get_cpu_lowcore(cpu) \
-        ((cpu)==smp_processor_id() ? S390_lowcore:(*lowcore_ptr[(cpu)]))
+        ((cpu) == smp_processor_id() ? &S390_lowcore : lowcore_ptr[(cpu)])
 #endif
 #endif /* __ASSEMBLY__ */
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/pgtable.h linux-2.4.19-pre3/include/asm-s390x/pgtable.h
--- linux-2.4.19-pre2/include/asm-s390x/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-s390x/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -38,6 +38,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)          do { } while (0)
 #define flush_icache_page(vma,pg)               do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
diff -urN linux-2.4.19-pre2/include/asm-s390x/processor.h linux-2.4.19-pre3/include/asm-s390x/processor.h
--- linux-2.4.19-pre2/include/asm-s390x/processor.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390x/processor.h	Mon Mar 11 14:13:30 2002
@@ -149,8 +149,8 @@
 }
 
 unsigned long get_wchan(struct task_struct *p);
-#define __KSTK_PTREGS(tsk) \
-	((struct pt_regs *)((unsigned long) tsk+THREAD_SIZE) - 1)
+#define __KSTK_PTREGS(tsk) ((struct pt_regs *) \
+        (((unsigned long) tsk + THREAD_SIZE - sizeof(struct pt_regs)) & -8L))
 #define KSTK_EIP(tsk)	(__KSTK_PTREGS(tsk)->psw.addr)
 #define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
@@ -182,6 +182,43 @@
 #define PSW_PROBLEM_STATE       0x0001000000000000UL
 
 /*
+ * Set PSW mask to specified value, while leaving the
+ * PSW addr pointing to the next instruction.
+ */
+
+static inline void __load_psw_mask (unsigned long mask)
+{
+	unsigned long addr;
+
+	psw_t psw;
+	psw.mask = mask;
+
+	asm volatile (
+		"    larl  %0,1f\n"
+		"    stg   %0,8(%1)\n"
+		"    lpswe 0(%1)\n"
+		"1:"
+		: "=&d" (addr) : "a" (&psw) : "memory", "cc" );
+}
+
+/*
+ * Function to stop a processor until an interruption occured
+ */
+static inline void enabled_wait(void)
+{
+	unsigned long reg;
+	psw_t wait_psw;
+
+	wait_psw.mask = 0x0706000180000000;
+	asm volatile (
+		"    larl  %0,0f\n"
+		"    stg   %0,8(%1)\n"
+		"    lpswe 0(%1)\n"
+		"0:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+/*
  * Function to drop a processor into disabled wait state
  */
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/ptrace.h linux-2.4.19-pre3/include/asm-s390x/ptrace.h
--- linux-2.4.19-pre2/include/asm-s390x/ptrace.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390x/ptrace.h	Mon Mar 11 14:13:30 2002
@@ -154,7 +154,6 @@
 	__u32 acrs[NUM_ACRS];
 	__u64 orig_gpr2;
 	__u32 trap;
-	__u32 old_ilc;
 } __attribute__ ((packed));
 
 /*
diff -urN linux-2.4.19-pre2/include/asm-s390x/rwsem.h linux-2.4.19-pre3/include/asm-s390x/rwsem.h
--- linux-2.4.19-pre2/include/asm-s390x/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/include/asm-s390x/rwsem.h	Mon Mar 11 14:13:30 2002
@@ -0,0 +1,209 @@
+#ifndef _S390X_RWSEM_H
+#define _S390X_RWSEM_H
+
+/*
+ *  include/asm-s390x/rwsem.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
+ */
+
+/*
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed long		count;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+};
+
+#define RWSEM_UNLOCKED_VALUE	0x0000000000000000L
+#define RWSEM_ACTIVE_BIAS	0x0000000000000001L
+#define RWSEM_ACTIVE_MASK	0x00000000ffffffffL
+#define RWSEM_WAITING_BIAS	(-0x0000000100000000L)
+#define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+/*
+ * initialisation
+ */
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   aghi %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (old < 0)
+		rwsem_down_read_failed(sem);
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   ag   %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (old != 0)
+		rwsem_down_write_failed(sem);
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   aghi %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((int) new == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   ag   %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((int) new == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   agr  %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   agr  %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+	return new;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _S390X_RWSEM_H */
diff -urN linux-2.4.19-pre2/include/asm-s390x/siginfo.h linux-2.4.19-pre3/include/asm-s390x/siginfo.h
--- linux-2.4.19-pre2/include/asm-s390x/siginfo.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390x/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -115,6 +115,7 @@
 #define SI_MESGQ	-3	/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-s390x/sigp.h linux-2.4.19-pre3/include/asm-s390x/sigp.h
--- linux-2.4.19-pre2/include/asm-s390x/sigp.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390x/sigp.h	Mon Mar 11 14:13:30 2002
@@ -130,6 +130,6 @@
    return ccode;
 }
 
-#endif __SIGP__
+#endif /* __SIGP__ */
 
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/spinlock.h linux-2.4.19-pre3/include/asm-s390x/spinlock.h
--- linux-2.4.19-pre2/include/asm-s390x/spinlock.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre3/include/asm-s390x/spinlock.h	Mon Mar 11 14:13:30 2002
@@ -29,22 +29,24 @@
 
 extern inline void spin_lock(spinlock_t *lp)
 {
-        __asm__ __volatile("    bras  1,1f\n"
+	unsigned long reg1, reg2;
+        __asm__ __volatile("    bras  %1,1f\n"
                            "0:  # diag  0,0,68\n"
-                           "1:  slr   0,0\n"
-                           "    cs    0,1,0(%0)\n"
+                           "1:  slr   %0,%0\n"
+                           "    cs    %0,%1,0(%2)\n"
                            "    jl    0b\n"
-                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
+                           : "=&d" (reg1), "=&d" (reg2)
+                           : "a" (&lp->lock) : "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
 {
-	unsigned int result;
+	unsigned int result, reg;
 	__asm__ __volatile("    slr   %0,%0\n"
-			   "    basr  1,0\n"
-			   "0:  cs    %0,1,0(%1)"
-			   : "=&d" (result)
-			   : "a" (&lp->lock) : "1", "cc", "memory" );
+			   "    basr  %1,0\n"
+			   "0:  cs    %0,%1,0(%2)"
+			   : "=&d" (result), "=&d" (reg)
+			   : "a" (&lp->lock) : "cc", "memory" );
 	return !result;
 }
 
diff -urN linux-2.4.19-pre2/include/asm-s390x/system.h linux-2.4.19-pre3/include/asm-s390x/system.h
--- linux-2.4.19-pre2/include/asm-s390x/system.h	Wed Jul 25 14:12:03 2001
+++ linux-2.4.19-pre3/include/asm-s390x/system.h	Mon Mar 11 14:13:30 2002
@@ -12,6 +12,7 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #ifdef __KERNEL__
 #include <asm/lowcore.h>
 #endif
@@ -23,7 +24,7 @@
                 break;                                                       \
 	save_fp_regs(&prev->thread.fp_regs);                                 \
 	restore_fp_regs(&next->thread.fp_regs);              		     \
-	last = resume(&prev->thread,&next->thread);                          \
+	last = resume(prev,next);					     \
 } while (0)
 
 struct task_struct;
@@ -110,8 +111,6 @@
                                 : "+d" (x) : "a" (ptr)
                                 : "memory", "cc", "0" );
                         break;
-               default:
-                        abort();
         }
         return x;
 }
@@ -144,24 +143,24 @@
 #define __sti() ({ \
         unsigned long dummy; \
         __asm__ __volatile__ ( \
-                "stosm %0,0x03" : "=m" (dummy) : : "memory"); \
+                "stosm 0(%0),0x03" : : "a" (&dummy) : "memory"); \
         })
 
 #define __cli() ({ \
         unsigned long flags; \
         __asm__ __volatile__ ( \
-                "stnsm %0,0xFC" : "=m" (flags) : : "memory"); \
+                "stnsm 0(%0),0xFC" : : "a" (&flags) : "memory"); \
         flags; \
         })
 
 #define __save_flags(x) \
-        __asm__ __volatile__("stosm %0,0" : "=m" (x) : : "memory")
+        __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory")
 
 #define __restore_flags(x) \
-        __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
+        __asm__ __volatile__("ssm   0(%0)" : : "a" (&x) : "memory")
 
 #define __load_psw(psw) \
-        __asm__ __volatile__("lpswe %0" : : "m" (psw) : "cc" );
+        __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
diff -urN linux-2.4.19-pre2/include/asm-s390x/timex.h linux-2.4.19-pre3/include/asm-s390x/timex.h
--- linux-2.4.19-pre2/include/asm-s390x/timex.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/asm-s390x/timex.h	Mon Mar 11 14:13:30 2002
@@ -25,8 +25,16 @@
 {
 	cycles_t cycles;
 
-	__asm__("stck  %0" : "=m" (cycles) : : "cc");
+	__asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
 	return cycles >> 2;
 }
 
+static inline unsigned long long get_clock (void)
+{
+	unsigned long long clock;
+
+	__asm__("stck 0(%0)" : : "a" (&(clock)) : "memory", "cc");
+	return clock;
+}
+
 #endif
diff -urN linux-2.4.19-pre2/include/asm-s390x/unistd.h linux-2.4.19-pre3/include/asm-s390x/unistd.h
--- linux-2.4.19-pre2/include/asm-s390x/unistd.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.19-pre3/include/asm-s390x/unistd.h	Mon Mar 11 14:13:30 2002
@@ -181,6 +181,8 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64         220
+#define __NR_gettid		226
+#define __NR_tkill 	        227
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
diff -urN linux-2.4.19-pre2/include/asm-sh/ide.h linux-2.4.19-pre3/include/asm-sh/ide.h
--- linux-2.4.19-pre2/include/asm-sh/ide.h	Sat Sep  8 12:29:09 2001
+++ linux-2.4.19-pre3/include/asm-sh/ide.h	Mon Mar 11 14:13:30 2002
@@ -116,7 +116,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -urN linux-2.4.19-pre2/include/asm-sh/pgtable.h linux-2.4.19-pre3/include/asm-sh/pgtable.h
--- linux-2.4.19-pre2/include/asm-sh/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-sh/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -41,6 +41,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 #define flush_cache_sigtramp(vaddr)		do { } while (0)
 
 #define p3_cache_init()				do { } while (0)
@@ -64,6 +65,7 @@
 
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /* Initialization of P3 area for copy_user_page */
 extern void p3_cache_init(void);
diff -urN linux-2.4.19-pre2/include/asm-sh/siginfo.h linux-2.4.19-pre3/include/asm-sh/siginfo.h
--- linux-2.4.19-pre2/include/asm-sh/siginfo.h	Thu Jan  4 13:19:13 2001
+++ linux-2.4.19-pre3/include/asm-sh/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-sh/unistd.h linux-2.4.19-pre3/include/asm-sh/unistd.h
--- linux-2.4.19-pre2/include/asm-sh/unistd.h	Mon Oct  2 11:57:34 2000
+++ linux-2.4.19-pre3/include/asm-sh/unistd.h	Mon Mar 11 14:13:30 2002
@@ -231,6 +231,8 @@
 #define __NR_madvise		219
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
+#define __NR_gettid		222
+#define __NR_tkill		223
 
 /* user-visible error numbers are in the range -1 - -125: see <asm-sh/errno.h> */
 
diff -urN linux-2.4.19-pre2/include/asm-sparc/ide.h linux-2.4.19-pre3/include/asm-sparc/ide.h
--- linux-2.4.19-pre2/include/asm-sparc/ide.h	Mon Jun 19 17:59:39 2000
+++ linux-2.4.19-pre3/include/asm-sparc/ide.h	Mon Mar 11 14:13:30 2002
@@ -84,6 +84,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
 				      unsigned long flags, const char *name, void *devid)
diff -urN linux-2.4.19-pre2/include/asm-sparc/pgtable.h linux-2.4.19-pre3/include/asm-sparc/pgtable.h
--- linux-2.4.19-pre2/include/asm-sparc/pgtable.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/asm-sparc/pgtable.h	Mon Mar 11 14:13:30 2002
@@ -345,6 +345,7 @@
 extern unsigned int pg_iobits;
 
 #define flush_icache_page(vma, pg)      do { } while(0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
diff -urN linux-2.4.19-pre2/include/asm-sparc/siginfo.h linux-2.4.19-pre3/include/asm-sparc/siginfo.h
--- linux-2.4.19-pre2/include/asm-sparc/siginfo.h	Mon Jun 19 17:59:39 2000
+++ linux-2.4.19-pre3/include/asm-sparc/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -112,6 +112,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-sparc/unistd.h linux-2.4.19-pre3/include/asm-sparc/unistd.h
--- linux-2.4.19-pre2/include/asm-sparc/unistd.h	Sun Oct 21 10:36:54 2001
+++ linux-2.4.19-pre3/include/asm-sparc/unistd.h	Mon Mar 11 14:13:30 2002
@@ -271,6 +271,7 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_tkill              257
 
 #define _syscall0(type,name) \
 type name(void) \
diff -urN linux-2.4.19-pre2/include/asm-sparc64/ide.h linux-2.4.19-pre3/include/asm-sparc64/ide.h
--- linux-2.4.19-pre2/include/asm-sparc64/ide.h	Mon Oct  1 09:19:56 2001
+++ linux-2.4.19-pre3/include/asm-sparc64/ide.h	Mon Mar 11 14:13:30 2002
@@ -80,6 +80,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
 				      unsigned long flags, const char *name, void *devid)
diff -urN linux-2.4.19-pre2/include/asm-sparc64/siginfo.h linux-2.4.19-pre3/include/asm-sparc64/siginfo.h
--- linux-2.4.19-pre2/include/asm-sparc64/siginfo.h	Wed May 24 18:38:26 2000
+++ linux-2.4.19-pre3/include/asm-sparc64/siginfo.h	Mon Mar 11 14:13:30 2002
@@ -172,6 +172,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.4.19-pre2/include/asm-sparc64/unistd.h linux-2.4.19-pre3/include/asm-sparc64/unistd.h
--- linux-2.4.19-pre2/include/asm-sparc64/unistd.h	Sun Oct 21 10:36:54 2001
+++ linux-2.4.19-pre3/include/asm-sparc64/unistd.h	Mon Mar 11 14:13:30 2002
@@ -273,6 +273,7 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_tkill              256
 
 #define _syscall0(type,name) \
 type name(void) \
diff -urN linux-2.4.19-pre2/include/linux/auto_fs.h linux-2.4.19-pre3/include/linux/auto_fs.h
--- linux-2.4.19-pre2/include/linux/auto_fs.h	Thu Nov 22 11:46:40 2001
+++ linux-2.4.19-pre3/include/linux/auto_fs.h	Mon Mar 11 14:13:30 2002
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__)
+#if defined(__sparc__) || defined(__mips__) || defined(__s390__)
 typedef unsigned int autofs_wqt_t;
 #else
 typedef unsigned long autofs_wqt_t;
diff -urN linux-2.4.19-pre2/include/linux/crc32.h linux-2.4.19-pre3/include/linux/crc32.h
--- linux-2.4.19-pre2/include/linux/crc32.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre3/include/linux/crc32.h	Mon Mar 11 14:13:30 2002
@@ -0,0 +1,49 @@
+/*
+ * crc32.h for early Linux 2.4.19pre kernel inclusion
+ * This defines ether_crc_le() and ether_crc() as inline functions
+ * This is slated to change to using the library crc32 functions
+ * as kernel 2.5.2 included at some future date.
+ */
+#ifndef _LINUX_CRC32_H
+#define _LINUX_CRC32_H
+
+#include <linux/types.h>
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+	int crc = -1;
+	while (--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ?
+				 ethernet_polynomial : 0);
+		}
+	}
+	return crc;
+}
+
+#endif /* _LINUX_CRC32_H */
diff -urN linux-2.4.19-pre2/include/linux/hdreg.h linux-2.4.19-pre3/include/linux/hdreg.h
--- linux-2.4.19-pre2/include/linux/hdreg.h	Thu Nov 22 11:46:18 2001
+++ linux-2.4.19-pre3/include/linux/hdreg.h	Mon Mar 11 14:13:30 2002
@@ -6,104 +6,269 @@
  * Various sources.  
  */
 
-#define HD_IRQ 14		/* the standard disk interrupt */
+#define HD_IRQ 14			/* the standard disk interrupt */
 
 /* ide.c has its own port definitions in "ide.h" */
 
 /* Hd controller regs. Ref: IBM AT Bios-listing */
-#define HD_DATA		0x1f0	/* _CTL when writing */
-#define HD_ERROR	0x1f1	/* see err-bits */
-#define HD_NSECTOR	0x1f2	/* nr of sectors to read/write */
-#define HD_SECTOR	0x1f3	/* starting sector */
-#define HD_LCYL		0x1f4	/* starting cylinder */
-#define HD_HCYL		0x1f5	/* high byte of starting cyl */
-#define HD_CURRENT	0x1f6	/* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS	0x1f7	/* see status-bits */
-#define HD_FEATURE HD_ERROR	/* same io address, read=error, write=feature */
-#define HD_PRECOMP HD_FEATURE	/* obsolete use of this port - predates IDE */
-#define HD_COMMAND HD_STATUS	/* same io address, read=status, write=cmd */
+#define HD_DATA		0x1f0		/* _CTL when writing */
+#define HD_ERROR	0x1f1		/* see err-bits */
+#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
+#define HD_SECTOR	0x1f3		/* starting sector */
+#define HD_LCYL		0x1f4		/* starting cylinder */
+#define HD_HCYL		0x1f5		/* high byte of starting cyl */
+#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS	0x1f7		/* see status-bits */
+#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
+#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
+#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
 
-#define HD_CMD		0x3f6	/* used for resets */
-#define HD_ALTSTATUS	0x3f6	/* same as HD_STATUS but doesn't clear irq */
+#define HD_CMD		0x3f6		/* used for resets */
+#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
 
 /* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
 
 /* Bits of HD_STATUS */
-#define ERR_STAT	0x01
-#define INDEX_STAT	0x02
-#define ECC_STAT	0x04	/* Corrected error */
-#define DRQ_STAT	0x08
-#define SEEK_STAT	0x10
-#define WRERR_STAT	0x20
-#define READY_STAT	0x40
-#define BUSY_STAT	0x80
-
-/* Values for HD_COMMAND */
-#define WIN_RESTORE		0x10
-#define WIN_READ		0x20
-#define WIN_WRITE		0x30
-#define WIN_WRITE_VERIFY	0x3C
-#define WIN_VERIFY		0x40
-#define WIN_FORMAT		0x50
-#define WIN_INIT		0x60
-#define WIN_SEEK		0x70
-#define WIN_DIAGNOSE		0x90
-#define WIN_SPECIFY		0x91	/* set drive geometry translation */
-#define WIN_IDLEIMMEDIATE	0xE1	/* force drive to become "ready" */
-#define WIN_SETIDLE1		0xE3
-#define WIN_SETIDLE2		0x97
-
-#define WIN_STANDBYNOW1		0xE0
-#define WIN_STANDBYNOW2		0x94
-#define WIN_SLEEPNOW1		0xE6
-#define WIN_SLEEPNOW2		0x99
-#define WIN_CHECKPOWERMODE1	0xE5
-#define WIN_CHECKPOWERMODE2	0x98
-
-#define WIN_DOORLOCK		0xDE	/* lock door on removable drives */
-#define WIN_DOORUNLOCK		0xDF	/* unlock door on removable drives */
-
-#define WIN_MULTREAD		0xC4	/* read sectors using multiple mode */
-#define WIN_MULTWRITE		0xC5	/* write sectors using multiple mode */
-#define WIN_SETMULT		0xC6	/* enable/disable multiple mode */
-#define WIN_IDENTIFY		0xEC	/* ask drive to identify itself	*/
-#define WIN_IDENTIFY_DMA	0xEE	/* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES		0xEF	/* set special drive features */
-#define WIN_READDMA		0xC8	/* read sectors using DMA transfers */
-#define WIN_WRITEDMA		0xCA	/* write sectors using DMA transfers */
-
-#define WIN_QUEUED_SERVICE	0xA2	/* */
-#define WIN_READDMA_QUEUED	0xC7	/* read sectors using Queued DMA transfers */
-#define WIN_WRITEDMA_QUEUED	0xCC	/* write sectors using Queued DMA transfers */
-
-#define WIN_READ_BUFFER		0xE4	/* force read only 1 sector */
-#define WIN_WRITE_BUFFER	0xE8	/* force write only 1 sector */
-
-#define WIN_SMART		0xB0	/* self-monitoring and reporting */
-
-/* Additional drive command codes used by ATAPI devices. */
-#define WIN_PIDENTIFY		0xA1	/* identify ATAPI device	*/
-#define WIN_SRST		0x08	/* ATAPI soft reset command */
-#define WIN_PACKETCMD		0xA0	/* Send a packet command. */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
 
-#define DISABLE_SEAGATE		0xFB
-#define EXABYTE_ENABLE_NEST	0xF0
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
 
-/* WIN_SMART sub-commands */
+/*
+ * Command Header sizes for IOCTL commands
+ *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
+ */
+
+#if 0
+#include <asm/hdreg.h>
+typedef ide_ioreg_t task_ioreg_t;
+#else
+typedef unsigned char task_ioreg_t;
+#endif
+
+#define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
+
+#define IDE_DRIVE_TASK_INVALID		-1
+#define IDE_DRIVE_TASK_NO_DATA		0
+#define IDE_DRIVE_TASK_SET_XFER		1
+
+#define IDE_DRIVE_TASK_IN		2
+
+#define IDE_DRIVE_TASK_OUT		3
+#define IDE_DRIVE_TASK_RAW_WRITE	4
+
+struct hd_drive_cmd_hdr {
+	task_ioreg_t command;
+	task_ioreg_t sector_number;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+};
 
-#define SMART_READ_VALUES	0xd0
-#define SMART_READ_THRESHOLDS	0xd1
-#define SMART_AUTOSAVE		0xd2
-#define SMART_SAVE		0xd3
-#define SMART_IMMEDIATE_OFFLINE	0xd4
-#define SMART_READ_LOG_SECTOR	0xd5
-#define SMART_WRITE_LOG_SECTOR	0xd6
-#define SMART_WRITE_THRESHOLDS	0xd7
-#define SMART_ENABLE		0xd8
-#define SMART_DISABLE		0xd9
-#define SMART_STATUS		0xda
-#define SMART_AUTO_OFFLINE	0xdb
+typedef struct hd_drive_task_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t command;
+} task_struct_t;
+
+typedef struct hd_drive_hob_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t control;
+} hob_struct_t;
+
+typedef union ide_reg_valid_s {
+	unsigned all				: 16;
+	struct {
+		unsigned data			: 1;
+		unsigned error_feature		: 1;
+		unsigned sector			: 1;
+		unsigned nsector		: 1;
+		unsigned lcyl			: 1;
+		unsigned hcyl			: 1;
+		unsigned select			: 1;
+		unsigned status_command		: 1;
+
+		unsigned data_hob		: 1;
+		unsigned error_feature_hob	: 1;
+		unsigned sector_hob		: 1;
+		unsigned nsector_hob		: 1;
+		unsigned lcyl_hob		: 1;
+		unsigned hcyl_hob		: 1;
+		unsigned select_hob		: 1;
+		unsigned control_hob		: 1;
+	} b;
+} ide_reg_valid_t;
 
+/*
+ * Define standard taskfile in/out register
+ */
+#define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
+#define IDE_TASKFILE_STD_IN_FLAGS	0xFE
+#define IDE_HOB_STD_OUT_FLAGS		0xC0
+#define IDE_HOB_STD_IN_FLAGS		0xC0
+
+typedef struct ide_task_request_s {
+	task_ioreg_t	io_ports[8];
+	task_ioreg_t	hob_ports[8];
+	ide_reg_valid_t	out_flags;
+	ide_reg_valid_t	in_flags;
+	int		data_phase;
+	int		req_cmd;
+	unsigned long	out_size;
+	unsigned long	in_size;
+} ide_task_request_t;
+
+typedef struct ide_ioctl_request_s {
+	ide_task_request_t	*task_request;
+	unsigned char		*out_buffer;
+	unsigned char		*in_buffer;
+} ide_ioctl_request_t;
+
+#define TASKFILE_INVALID		0x7fff
+#define TASKFILE_48			0x8000
+
+#define TASKFILE_NO_DATA		0x0000
+
+#define TASKFILE_IN			0x0001
+#define TASKFILE_MULTI_IN		0x0002
+
+#define TASKFILE_OUT			0x0004
+#define TASKFILE_MULTI_OUT		0x0008
+#define TASKFILE_IN_OUT			0x0010
+
+#define TASKFILE_IN_DMA			0x0020
+#define TASKFILE_OUT_DMA		0x0040
+#define TASKFILE_IN_DMAQ		0x0080
+#define TASKFILE_OUT_DMAQ		0x0100
+
+#define TASKFILE_P_IN			0x0200
+#define TASKFILE_P_OUT			0x0400
+#define TASKFILE_P_IN_DMA		0x0800
+#define TASKFILE_P_OUT_DMA		0x1000
+#define TASKFILE_P_IN_DMAQ		0x2000
+#define TASKFILE_P_OUT_DMAQ		0x4000
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP				0x00
+#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+#define WIN_SRST			0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET		0x08
+#define WIN_RESTORE			0x10
+#define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_EXT			0x24 /* 48-Bit */
+#define WIN_READDMA_EXT			0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+#define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_EXT			0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+#define WIN_FORMAT			0x50
+#define WIN_INIT			0x60
+#define WIN_SEEK			0x70
+#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE			0x90
+#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE		0x92
+#define WIN_STANDBYNOW2			0x94
+#define WIN_SETIDLE2			0x97
+#define WIN_CHECKPOWERMODE2		0x98
+#define WIN_SLEEPNOW2			0x99
+#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
+#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_SMART			0xB0 /* self-monitoring and reporting */
+#define CFA_ERASE_SECTORS       	0xC0
+#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1			0xE0
+#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1			0xE3
+#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1		0xE5
+#define WIN_SLEEPNOW1			0xE6
+#define WIN_FLUSH_CACHE			0xE7
+#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
+#define WIN_MEDIAEJECT			0xED
+#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES			0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST		0xF0
+#define WIN_SECURITY_SET_PASS		0xF1
+#define WIN_SECURITY_UNLOCK		0xF2
+#define WIN_SECURITY_ERASE_PREPARE	0xF3
+#define WIN_SECURITY_ERASE_UNIT		0xF4
+#define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define WIN_SECURITY_DISABLE		0xF6
+#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
+#define WIN_SET_MAX			0xF9
+#define DISABLE_SEAGATE			0xFB
+
+/* WIN_SMART sub-commands */
+
+#define SMART_READ_VALUES		0xD0
+#define SMART_READ_THRESHOLDS		0xD1
+#define SMART_AUTOSAVE			0xD2
+#define SMART_SAVE			0xD3
+#define SMART_IMMEDIATE_OFFLINE		0xD4
+#define SMART_READ_LOG_SECTOR		0xD5
+#define SMART_WRITE_LOG_SECTOR		0xD6
+#define SMART_WRITE_THRESHOLDS		0xD7
+#define SMART_ENABLE			0xD8
+#define SMART_DISABLE			0xD9
+#define SMART_STATUS			0xDA
+#define SMART_AUTO_OFFLINE		0xDB
+
+/* Password used in TF4 & TF5 executing SMART commands */
+
+#define SMART_LCYL_PASS			0x4F
+#define SMART_HCYL_PASS			0xC2
+		
 /* WIN_SETFEATURES sub-commands */
 
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
@@ -131,6 +296,7 @@
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
@@ -141,29 +307,19 @@
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
 #define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
 #define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
 
 /* WIN_SECURITY sub-commands */
 
-#define SECURITY_SET_PASSWORD		0xBA	/* 0xF1 */
-#define SECURITY_UNLOCK			0xBB	/* 0xF2 */
-#define SECURITY_ERASE_PREPARE		0xBC	/* 0xF3 */
-#define SECURITY_ERASE_UNIT		0xBD	/* 0xF4 */
-#define SECURITY_FREEZE_LOCK		0xBE	/* 0xF5 */
-#define SECURITY_DISABLE_PASSWORD	0xBF	/* 0xF6 */
-
-/* Bits for HD_ERROR */
-#define MARK_ERR	0x01	/* Bad address mark */
-#define TRK0_ERR	0x02	/* couldn't find track 0 */
-#define ABRT_ERR	0x04	/* Command aborted */
-#define MCR_ERR		0x08	/* media change request */
-#define ID_ERR		0x10	/* ID field not found */
-#define MC_ERR		0x20	/* media changed */
-#define ECC_ERR		0x40	/* Uncorrectable ECC error */
-#define	BBD_ERR		0x80	/* pre-EIDE meaning:  block marked bad */
-#define	ICRC_ERR	0x80	/* new meaning:  CRC error during transfer */
+#define SECURITY_SET_PASSWORD		0xBA
+#define SECURITY_UNLOCK			0xBB
+#define SECURITY_ERASE_PREPARE		0xBC
+#define SECURITY_ERASE_UNIT		0xBD
+#define SECURITY_FREEZE_LOCK		0xBE
+#define SECURITY_DISABLE_PASSWORD	0xBF
 
 struct hd_geometry {
       unsigned char heads;
@@ -172,6 +328,14 @@
       unsigned long start;
 };
 
+/* BIG GEOMETRY */
+struct hd_big_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	unsigned long start;
+};
+
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
@@ -186,9 +350,10 @@
 #define HDIO_GET_IDENTITY	0x030d	/* get IDE identification info */
 #define HDIO_GET_WCACHE		0x030e	/* get write cache mode on|off */
 #define HDIO_GET_ACOUSTIC	0x030f	/* get acoustic value */
+#define	HDIO_GET_ADDRESS	0x0310	/* */
 
 #define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
-#define HDIO_TRISTATE_HWIF	0x031b	/* OBSOLETE - use SET_BUSSTATE */
+#define HDIO_TRISTATE_HWIF	0x031b	/* execute a channel tristate */
 #define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
 #define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
 #define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
@@ -211,6 +376,7 @@
 #define HDIO_SET_ACOUSTIC	0x032c	/* change acoustic behavior */
 #define HDIO_SET_BUSSTATE	0x032d	/* set the bus state of the hwif */
 #define HDIO_SET_QDMA		0x032e	/* change use-qdma flag */
+#define HDIO_SET_ADDRESS	0x032f	/* change lba addressing modes */
 
 /* bus states */
 enum {
@@ -219,34 +385,30 @@
 	BUSSTATE_TRISTATE
 };
 
-/* BIG GEOMETRY */
-struct hd_big_geometry {
-	unsigned char heads;
-	unsigned char sectors;
-	unsigned int cylinders;
-	unsigned long start;
-};
-
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
 #define __NEW_HD_DRIVE_ID
-/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
+/* structure returned by HDIO_GET_IDENTITY,
+ * as per ANSI NCITS ATA6 rev.1b spec
+ */
 struct hd_driveid {
 	unsigned short	config;		/* lots of obsolete bit flags */
-	unsigned short	cyls;		/* "physical" cyls */
+	unsigned short	cyls;		/* Obsolete, "physical" cyls */
 	unsigned short	reserved2;	/* reserved (word 2) */
-	unsigned short	heads;		/* "physical" heads */
+	unsigned short	heads;		/* Obsolete, "physical" heads */
 	unsigned short	track_bytes;	/* unformatted bytes per track */
 	unsigned short	sector_bytes;	/* unformatted bytes per sector */
-	unsigned short	sectors;	/* "physical" sectors per track */
+	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
 	unsigned short	vendor0;	/* vendor unique */
 	unsigned short	vendor1;	/* vendor unique */
-	unsigned short	vendor2;	/* vendor unique */
+	unsigned short	vendor2;	/* Retired vendor unique */
 	unsigned char	serial_no[20];	/* 0 = not_specified */
-	unsigned short	buf_type;
-	unsigned short	buf_size;	/* 512 byte increments; 0 = not_specified */
+	unsigned short	buf_type;	/* Retired */
+	unsigned short	buf_size;	/* Retired, 512 byte increments
+					 * 0 = not_specified
+					 */
 	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
 	unsigned char	fw_rev[8];	/* 0 = not_specified */
 	unsigned char	model[40];	/* 0 = not_specified */
@@ -254,72 +416,223 @@
 	unsigned char	vendor3;	/* vendor unique */
 	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
 	unsigned char	vendor4;	/* vendor unique */
-	unsigned char	capability;	/* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
+	unsigned char	capability;	/* (upper byte of word 49)
+					 *  3:	IORDYsup
+					 *  2:	IORDYsw
+					 *  1:	LBA
+					 *  0:	DMA
+					 */
 	unsigned short	reserved50;	/* reserved (word 50) */
-	unsigned char	vendor5;	/* vendor unique */
-	unsigned char	tPIO;		/* 0=slow, 1=medium, 2=fast */
-	unsigned char	vendor6;	/* vendor unique */
-	unsigned char	tDMA;		/* 0=slow, 1=medium, 2=fast */
-	unsigned short	field_valid;	/* bits 0:cur_ok 1:eide_ok */
-	unsigned short	cur_cyls;	/* logical cylinders */
-	unsigned short	cur_heads;	/* logical heads */
-	unsigned short	cur_sectors;	/* logical sectors per track */
-	unsigned short	cur_capacity0;	/* logical total sectors on drive */
-	unsigned short	cur_capacity1;	/*  (2 words, misaligned int)     */
+	unsigned char	vendor5;	/* Obsolete, vendor unique */
+	unsigned char	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned char	vendor6;	/* Obsolete, vendor unique */
+	unsigned char	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned short	field_valid;	/* (word 53)
+					 *  2:	ultra_ok	word  88
+					 *  1:	eide_ok		words 64-70
+					 *  0:	cur_ok		words 54-58
+					 */
+	unsigned short	cur_cyls;	/* Obsolete, logical cylinders */
+	unsigned short	cur_heads;	/* Obsolete, l heads */
+	unsigned short	cur_sectors;	/* Obsolete, l sectors per track */
+	unsigned short	cur_capacity0;	/* Obsolete, l total sectors on drive */
+	unsigned short	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
 	unsigned char	multsect;	/* current multiple sector count */
 	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
-	unsigned int	lba_capacity;	/* total number of sectors */
-	unsigned short	dma_1word;	/* single-word dma info */
+	unsigned int	lba_capacity;	/* Obsolete, total number of sectors */
+	unsigned short	dma_1word;	/* Obsolete, single-word dma info */
 	unsigned short	dma_mword;	/* multiple-word dma info */
 	unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
 	unsigned short  eide_dma_min;	/* min mword dma cycle time (ns) */
 	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
 	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
 	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
-	unsigned short	words69_70[2];	/* reserved words 69-70 */
+	unsigned short	words69_70[2];	/* reserved words 69-70
+					 * future command overlap and queuing
+					 */
 	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
-	unsigned short	words71_74[4];	/* reserved words 71-74 */
-	unsigned short  queue_depth;	/*  */
+	unsigned short	words71_74[4];	/* reserved words 71-74
+					 * for IDENTIFY PACKET DEVICE command
+					 */
+	unsigned short  queue_depth;	/* (word 75)
+					 * 15:5	reserved
+					 *  4:0	Maximum queue depth -1
+					 */
 	unsigned short  words76_79[4];	/* reserved words 76-79 */
-	unsigned short  major_rev_num;	/*  */
-	unsigned short  minor_rev_num;	/*  */
-	unsigned short  command_set_1;	/* bits 0:Smart 1:Security 2:Removable 3:PM */
-	unsigned short  command_set_2;	/* bits 14:Smart Enabled 13:0 zero */
-	unsigned short  cfsse;		/* command set-feature supported extensions */
-	unsigned short  cfs_enable_1;	/* command set-feature enabled */
-	unsigned short  cfs_enable_2;	/* command set-feature enabled */
-	unsigned short  csf_default;	/* command set-feature default */
-	unsigned short  dma_ultra;	/*  */
+	unsigned short  major_rev_num;	/* (word 80) */
+	unsigned short  minor_rev_num;	/* (word 81) */
+	unsigned short  command_set_1;	/* (word 82) supported
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  command_set_2;	/* (word 83)
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  cfsse;		/* (word 84)
+					 * cmd set-feature supported extensions
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  cfs_enable_1;	/* (word 85)
+					 * command set-feature enabled
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  cfs_enable_2;	/* (word 86)
+					 * command set-feature enabled
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  csf_default;	/* (word 87)
+					 * command set-feature default
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  dma_ultra;	/* (word 88) */
 	unsigned short	word89;		/* reserved (word 89) */
 	unsigned short	word90;		/* reserved (word 90) */
 	unsigned short	CurAPMvalues;	/* current APM values */
 	unsigned short	word92;		/* reserved (word 92) */
-	unsigned short	hw_config;	/* hardware config */
-	unsigned short  words94_125[32];/* reserved words 94-125 */
-	unsigned short	last_lun;	/* reserved (word 126) */
-	unsigned short	word127;	/* reserved (word 127) */
-	unsigned short	dlf;		/* device lock function
+	unsigned short	hw_config;	/* hardware config (word 93)
+					 * 15:
+					 * 14:
+					 * 13:
+					 * 12:
+					 * 11:
+					 * 10:
+					 *  9:
+					 *  8:
+					 *  7:
+					 *  6:
+					 *  5:
+					 *  4:
+					 *  3:
+					 *  2:
+					 *  1:
+					 *  0:
+					 */
+	unsigned short	acoustic;	/* (word 94)
+					 * 15:8	Vendor's recommended value
+					 *  7:0	current value
+					 */
+	unsigned short	words95_99[5];	/* reserved words 95-99 */
+#if 0
+	unsigned short	words100_103[4]	;/* reserved words 100-103 */
+#else
+	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+#endif
+	unsigned short	words104_125[22];/* reserved words 104-125 */
+	unsigned short	last_lun;	/* (word 126) */
+	unsigned short	word127;	/* (word 127) Feature Set
+					 * Removable Media Notification
+					 * 15:2	reserved
+					 *  1:0	00 = not supported
+					 *	01 = supported
+					 *	10 = reserved
+					 *	11 = reserved
+					 */
+	unsigned short	dlf;		/* (word 128)
+					 * device lock function
 					 * 15:9	reserved
-					 * 8	security level 1:max 0:high
-					 * 7:6	reserved
-					 * 5	enhanced erase
-					 * 4	expire
-					 * 3	frozen
-					 * 2	locked
-					 * 1	en/disabled
-					 * 0	capability
+					 *  8	security level 1:max 0:high
+					 *  7:6	reserved
+					 *  5	enhanced erase
+					 *  4	expire
+					 *  3	frozen
+					 *  2	locked
+					 *  1	en/disabled
+					 *  0	capability
 					 */
-	unsigned short  csfo;		/* current set features options
+	unsigned short  csfo;		/*  (word 129)
+					 * current set features options
 					 * 15:4	reserved
-					 * 3	auto reassign
-					 * 2	reverting
-					 * 1	read-look-ahead
-					 * 0	write cache
+					 *  3:	auto reassign
+					 *  2:	reverting
+					 *  1:	read-look-ahead
+					 *  0:	write cache
 					 */
 	unsigned short	words130_155[26];/* reserved vendor words 130-155 */
-	unsigned short	word156;
+	unsigned short	word156;	/* reserved vendor word 156 */
 	unsigned short	words157_159[3];/* reserved vendor words 157-159 */
-	unsigned short	words160_255[95];/* reserved words 160-255 */
+	unsigned short	cfa_power;	/* (word 160) CFA Power Mode
+					 * 15 word 160 supported
+					 * 14 reserved
+					 * 13
+					 * 12
+					 * 11:0
+					 */
+	unsigned short	words161_175[14];/* Reserved for CFA */
+	unsigned short	words176_205[31];/* Current Media Serial Number */
+	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	integrity_word;	/* (word 255)
+					 * 15:8 Checksum
+					 *  7:0 Signature
+					 */
 };
 
 /*
diff -urN linux-2.4.19-pre2/include/linux/ide.h linux-2.4.19-pre3/include/linux/ide.h
--- linux-2.4.19-pre2/include/linux/ide.h	Thu Nov 22 11:48:07 2001
+++ linux-2.4.19-pre3/include/linux/ide.h	Mon Mar 11 14:13:30 2002
@@ -65,13 +65,14 @@
 /*
  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  */
-#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/
+#define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
+
+#define IDE_DRIVE_TASK			98
 
 /*
- * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
+ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
  */
-#define IDE_DRIVE_TASK		98
-#define IDE_DRIVE_CMD_AEB	98
+#define IDE_DRIVE_TASKFILE		97
 
 /*
  *  "No user-serviceable parts" beyond this point  :)
@@ -120,6 +121,17 @@
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
 
+#define IDE_DATA_OFFSET_HOB	(0)
+#define IDE_ERROR_OFFSET_HOB	(1)
+#define IDE_NSECTOR_OFFSET_HOB	(2)
+#define IDE_SECTOR_OFFSET_HOB	(3)
+#define IDE_LCYL_OFFSET_HOB	(4)
+#define IDE_HCYL_OFFSET_HOB	(5)
+#define IDE_SELECT_OFFSET_HOB	(6)
+#define IDE_CONTROL_OFFSET_HOB	(7)
+
+#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
+
 #define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
 #define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
 #define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -131,6 +143,16 @@
 #define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
 #define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
 
+#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+
 #define IDE_FEATURE_REG		IDE_ERROR_REG
 #define IDE_COMMAND_REG		IDE_STATUS_REG
 #define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
@@ -156,11 +178,21 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */
+#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
+#define SECTOR_SIZE	512
+#define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
+#ifndef SPLIT_WORD
+#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
+#endif
+#ifndef MAKE_WORD
+#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
+#endif
+
+
 /*
  * Timeouts for various operations:
  */
@@ -170,8 +202,7 @@
 #else
 #define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
 #endif /* CONFIG_APM || CONFIG_APM_MODULE */
-#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?)
-				            if all ATAPI CD is closed at boot */
+#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
 #define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
@@ -209,6 +240,11 @@
 		(drive)->quirk_list = hwif->quirkproc(drive);	\
 }
 
+#define HOST(hwif,chipset)					\
+{								\
+	return ((hwif)->chipset == chipset) ? 1 : 0;		\
+}
+
 #define IDE_DEBUG(lineno) \
 	printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
 
@@ -223,6 +259,18 @@
 #endif
 
 /*
+ * hwif_chipset_t is used to keep track of the specific hardware
+ * chipset used by each IDE interface, if known.
+ */
+typedef enum {	ide_unknown,	ide_generic,	ide_pci,
+		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
+		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
+		ide_pdc4030,	ide_rz1000,	ide_trm290,
+		ide_cmd646,	ide_cy82c693,	ide_4drives,
+		ide_pmac,	ide_etrax100
+} hwif_chipset_t;
+
+/*
  * Structure to hold all information about the location of this port
  */
 typedef struct hw_regs_s {
@@ -231,6 +279,7 @@
 	int		dma;			/* our dma entry */
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
 	void		*priv;			/* interface specific data */
+	hwif_chipset_t  chipset;
 } hw_regs_t;
 
 /*
@@ -259,16 +308,20 @@
 #ifndef HAVE_ARCH_OUT_BYTE
 #ifdef REALLY_FAST_IO
 #define OUT_BYTE(b,p)          outb((b),(p))
+#define OUT_WORD(w,p)          outw((w),(p))
 #else
 #define OUT_BYTE(b,p)          outb_p((b),(p))
+#define OUT_WORD(w,p)          outw_p((w),(p))
 #endif
 #endif
 
 #ifndef HAVE_ARCH_IN_BYTE
 #ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb_p(p)
-#else
 #define IN_BYTE(p)             (byte)inb(p)
+#define IN_WORD(p)             (short)inw(p)
+#else
+#define IN_BYTE(p)             (byte)inb_p(p)
+#define IN_WORD(p)             (short)inw_p(p)
 #endif
 #endif
 
@@ -328,6 +381,7 @@
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
+	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
 	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
 	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
@@ -340,7 +394,7 @@
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		nowerr;		/* used for ignoring WRERR_STAT */
 	byte		sect0;		/* offset of first sector for DM6:DDO */
-	byte 		usage;		/* current "open()" count for drive */
+	unsigned int	usage;		/* current "open()" count for drive */
 	byte 		head;		/* "real" number of heads */
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
@@ -348,6 +402,7 @@
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
 	unsigned long	capacity;	/* total number of sectors */
+	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
 	void		  *hwif;	/* actually (ide_hwif_t *) */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
@@ -369,6 +424,8 @@
 	byte		init_speed;	/* transfer rate set at boot */
 	byte		current_speed;	/* current transfer rate set */
 	byte		dn;		/* now wide spread use */
+	byte		wcache;		/* status of write cache */
+	byte		acoustic;	/* acoustic management */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
 } ide_drive_t;
@@ -438,19 +495,7 @@
 /*
  * ide soft-power support
  */
-typedef int (ide_busproc_t) (struct hwif_s *, int);
-
-/*
- * hwif_chipset_t is used to keep track of the specific hardware
- * chipset used by each IDE interface, if known.
- */
-typedef enum {	ide_unknown,	ide_generic,	ide_pci,
-		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
-		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
-		ide_pdc4030,	ide_rz1000,	ide_trm290,
-		ide_cmd646,	ide_cy82c693,	ide_4drives,
-		ide_pmac,       ide_etrax100
-} hwif_chipset_t;
+typedef int (ide_busproc_t) (ide_drive_t *, int);
 
 #define IDE_CHIPSET_PCI_MASK	\
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
@@ -521,7 +566,6 @@
 	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
-
 /*
  * Status returned from various ide_ functions
  */
@@ -533,7 +577,9 @@
 /*
  *  internal ide interrupt handler type
  */
+typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
 
 /*
  * when ide_timer_expiry fires, invoke a handler of this type
@@ -554,6 +600,8 @@
 	ide_expiry_t		*expiry;	/* queried upon timeouts */
 } ide_hwgroup_t;
 
+/* structure attached to the request for IDE_TASK_CMDS */
+
 /*
  * configurable drive settings
  */
@@ -604,6 +652,8 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
+void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
 void destroy_proc_ide_drives(ide_hwif_t *);
 void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
@@ -636,6 +686,8 @@
 #define IDE_SUBDRIVER_VERSION	1
 
 typedef int		(ide_cleanup_proc)(ide_drive_t *);
+typedef int		(ide_standby_proc)(ide_drive_t *);
+typedef int		(ide_flushcache_proc)(ide_drive_t *);
 typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
 typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
 typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
@@ -647,7 +699,9 @@
 typedef unsigned long	(ide_capacity_proc)(ide_drive_t *);
 typedef ide_startstop_t	(ide_special_proc)(ide_drive_t *);
 typedef void		(ide_setting_proc)(ide_drive_t *);
-typedef int		(ide_driver_reinit_proc)(ide_drive_t *);
+typedef int		(ide_reinit_proc)(ide_drive_t *);
+typedef void		(ata_prebuilder_proc)(ide_drive_t *);
+typedef void		(atapi_prebuilder_proc)(ide_drive_t *);
 
 typedef struct ide_driver_s {
 	const char			*name;
@@ -657,6 +711,8 @@
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
 	ide_cleanup_proc		*cleanup;
+	ide_standby_proc		*standby;
+	ide_flushcache_proc		*flushcache;
 	ide_do_request_proc		*do_request;
 	ide_end_request_proc		*end_request;
 	ide_ioctl_proc			*ioctl;
@@ -668,7 +724,9 @@
 	ide_capacity_proc		*capacity;
 	ide_special_proc		*special;
 	ide_proc_entry_t		*proc;
-	ide_driver_reinit_proc		*driver_reinit;
+	ide_reinit_proc			*reinit;
+	ata_prebuilder_proc		*ata_prebuilder;
+	atapi_prebuilder_proc		*atapi_prebuilder;
 } ide_driver_t;
 
 #define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
@@ -727,6 +785,8 @@
 void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
 void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
 
+int drive_is_ready (ide_drive_t *drive);
+
 /*
  * This is used on exit from the driver, to designate the next irq handler
  * and also to start the safety timer.
@@ -748,7 +808,7 @@
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
 
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
@@ -843,24 +903,92 @@
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
  */
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
 /*
- * Issue ATA command and wait for completion.
+ * Issue ATA command and wait for completion. use for implementing commands in kernel
  */
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+
 int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
+ 
+typedef struct ide_task_s {
+	task_ioreg_t		tfRegister[8];
+	task_ioreg_t		hobRegister[8];
+	ide_reg_valid_t		tf_out_flags;
+	ide_reg_valid_t		tf_in_flags;
+	int			data_phase;
+	int			command_type;
+	ide_pre_handler_t	*prehandler;
+	ide_handler_t		*handler;
+	ide_post_handler_t	*posthandler;
+	void			*special;	/* valid_t generally */
+	struct request		*rq;		/* copy of request */
+	unsigned long		block;		/* copy of block */
+} ide_task_t;
+
+typedef struct pkt_task_s {
+	task_ioreg_t		tfRegister[8];
+	int			data_phase;
+	int			command_type;
+	ide_handler_t		*handler;
+	void			*special;
+	struct request		*rq;		/* copy of request */
+	unsigned long		block;		/* copy of block */
+} pkt_task_t;
+
+/*
+ * taskfile io for disks for now...
+ */
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+/*
+ * Builds request from ide_ioctl
+ */
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+
+/*
+ * Special Flagged Register Validation Caller
+ */
+// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+ide_startstop_t set_multmode_intr (ide_drive_t *drive);
+ide_startstop_t set_geometry_intr (ide_drive_t *drive);
+ide_startstop_t recal_intr (ide_drive_t *drive);
+ide_startstop_t task_no_data_intr (ide_drive_t *drive);
+ide_startstop_t task_in_intr (ide_drive_t *drive);
+ide_startstop_t task_mulin_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_out_intr (ide_drive_t *drive);
+ide_startstop_t task_mulout_intr (ide_drive_t *drive);
+void ide_init_drive_taskfile (struct request *rq);
+
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+/* Expects args is a full set of TF registers and parses the command type */
+int ide_cmd_type_parser (ide_task_t *args);
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
 
 void ide_delay_50ms (void);
 int system_bus_clock(void);
 
 byte ide_auto_reduce_xfer (ide_drive_t *drive);
 int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
 int ide_config_drive_speed (ide_drive_t *drive, byte speed);
 byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int set_transfer (ide_drive_t *drive, ide_task_t *args);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -905,23 +1033,30 @@
 extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
+int ide_reinit_drive (ide_drive_t *drive);
+
 #ifdef _IDE_C
 #ifdef CONFIG_BLK_DEV_IDE
 int ideprobe_init (void);
 #endif /* CONFIG_BLK_DEV_IDE */
 #ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_reinit (ide_drive_t *drive);
 int idedisk_init (void);
 #endif /* CONFIG_BLK_DEV_IDEDISK */
 #ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_reinit (ide_drive_t *drive);
 int ide_cdrom_init (void);
 #endif /* CONFIG_BLK_DEV_IDECD */
 #ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_reinit (ide_drive_t *drive);
 int idetape_init (void);
 #endif /* CONFIG_BLK_DEV_IDETAPE */
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_reinit (ide_drive_t *drive);
 int idefloppy_init (void);
 #endif /* CONFIG_BLK_DEV_IDEFLOPPY */
 #ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_reinit (ide_drive_t *drive);
 int idescsi_init (void);
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 #endif /* _IDE_C */
@@ -961,4 +1096,7 @@
 
 void hwif_unregister (ide_hwif_t *hwif);
 
+void export_ide_init_queue (ide_drive_t *drive);
+byte export_probe_for_drive (ide_drive_t *drive);
+
 #endif /* _IDE_H */
diff -urN linux-2.4.19-pre2/include/linux/mm.h linux-2.4.19-pre3/include/linux/mm.h
--- linux-2.4.19-pre2/include/linux/mm.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/linux/mm.h	Mon Mar 11 14:13:30 2002
@@ -15,6 +15,7 @@
 
 extern unsigned long max_mapnr;
 extern unsigned long num_physpages;
+extern unsigned long num_mappedpages;
 extern void * high_memory;
 extern int page_cluster;
 /* The inactive_clean lists are per zone. */
diff -urN linux-2.4.19-pre2/include/linux/pm.h linux-2.4.19-pre3/include/linux/pm.h
--- linux-2.4.19-pre2/include/linux/pm.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre3/include/linux/pm.h	Mon Mar 11 14:13:31 2002
@@ -103,8 +103,8 @@
 	void		*data;
 
 	unsigned long	 flags;
-	int		 state;
-	int		 prev_state;
+	unsigned long	 state;
+	unsigned long	 prev_state;
 
 	struct list_head entry;
 };
diff -urN linux-2.4.19-pre2/include/linux/reiserfs_fs.h linux-2.4.19-pre3/include/linux/reiserfs_fs.h
--- linux-2.4.19-pre2/include/linux/reiserfs_fs.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/linux/reiserfs_fs.h	Mon Mar 11 14:13:31 2002
@@ -204,7 +204,15 @@
 #define REISERFS_VALID_FS    1
 #define REISERFS_ERROR_FS    2
 
-
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3 
+#define TYPE_MAXTYPE 3 
+#define TYPE_ANY 15 // FIXME: comment is required
 
 /***************************************************************************/
 /*                       KEY & ITEM HEAD                                   */
@@ -240,7 +248,7 @@
 {
     offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
     tmp.linear = le64_to_cpu( tmp.linear );
-    return tmp.offset_v2.k_type;
+    return (tmp.offset_v2.k_type <= TYPE_MAXTYPE)?tmp.offset_v2.k_type:TYPE_ANY;
 }
  
 static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type )
@@ -390,15 +398,6 @@
 #define put_block_num(p, i, v) put_unaligned(cpu_to_le32(v), (p) + (i))
 
 //
-// there are 5 item types currently
-//
-#define TYPE_STAT_DATA 0
-#define TYPE_INDIRECT 1
-#define TYPE_DIRECT 2
-#define TYPE_DIRENTRY 3 
-#define TYPE_ANY 15 // FIXME: comment is required
-
-//
 // in old version uniqueness field shows key type
 //
 #define V1_SD_UNIQUENESS 0
@@ -718,11 +717,41 @@
 #define set_sd_v1_first_direct_byte(sdp,v) \
                                 ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
 
+#include <linux/ext2_fs.h>
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+   so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_SYNC_FL      EXT2_SYNC_FL
+#define REISERFS_NOATIME_FL   EXT2_NOATIME_FL
+#define REISERFS_NODUMP_FL    EXT2_NODUMP_FL
+#define REISERFS_SECRM_FL     EXT2_SECRM_FL
+#define REISERFS_UNRM_FL      EXT2_UNRM_FL
+#define REISERFS_COMPR_FL     EXT2_COMPR_FL
+/* persistent flag to disable tails on per-file basic.
+   Note, that is inheritable: mark directory with this and
+   all new files inside will not have tails. 
+
+   Teodore Tso allocated EXT2_NODUMP_FL (0x00008000) for this. Change
+   numeric constant to ext2 macro when available. */
+#define REISERFS_NOTAIL_FL    (0x00008000) /* EXT2_NOTAIL_FL */
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |	\
+				REISERFS_SYNC_FL |	\
+				REISERFS_NOATIME_FL |	\
+				REISERFS_NODUMP_FL |	\
+				REISERFS_SECRM_FL |	\
+				REISERFS_COMPR_FL |	\
+				REISERFS_NOTAIL_FL )
+
 /* Stat Data on disk (reiserfs version of UFS disk inode minus the
    address blocks) */
 struct stat_data {
     __u16 sd_mode;	/* file type, permissions */
-    __u16 sd_reserved;
+    __u16 sd_attrs;     /* persistent inode flags */
     __u32 sd_nlink;	/* number of hard links */
     __u64 sd_size;	/* file size */
     __u32 sd_uid;		/* owner */
@@ -775,6 +804,8 @@
 #define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
 #define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
 #define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
 
 
 /***************************************************************************/
@@ -1365,7 +1396,7 @@
 
 extern struct item_operations stat_data_ops, indirect_ops, direct_ops, 
   direntry_ops;
-extern struct item_operations * item_ops [4];
+extern struct item_operations * item_ops [TYPE_ANY + 1];
 
 #define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
 #define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
@@ -1701,6 +1732,9 @@
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
 void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
 
+void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode );
+void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs );
+
 /* namei.c */
 inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
 int search_by_entry_key (struct super_block * sb, const struct cpu_key * key, 
@@ -1792,8 +1826,14 @@
 				     int n_size);
 
 /* fix_nodes.c */
+#ifdef CONFIG_REISERFS_CHECK
 void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s);
 void reiserfs_kfree (const void * vp, size_t size, struct super_block * s);
+#else
+#define reiserfs_kmalloc(x, y, z) kmalloc(x, y)
+#define reiserfs_kfree(x, y, z) kfree(x)
+#endif
+
 int fix_nodes (int n_op_mode, struct tree_balance * p_s_tb, 
 	       struct item_head * p_s_ins_ih, const void *);
 void unfix_nodes (struct tree_balance *);
@@ -1824,6 +1864,7 @@
 void check_leaf (struct buffer_head * bh);
 void check_internal (struct buffer_head * bh);
 void print_statistics (struct super_block * s);
+char * reiserfs_hashname(int code);
 
 /* lbalance.c */
 int leaf_move_items (int shift_mode, struct tree_balance * tb, int mov_num, int mov_bytes, struct buffer_head * Snew);
@@ -1918,6 +1959,12 @@
  
 /* ioctl's command */
 #define REISERFS_IOC_UNPACK		_IOW(0xCD,1,long)
+/* define following flags to be the same as in ext2, so that chattr(1),
+   lsattr(1) will work with us. */
+#define REISERFS_IOC_GETFLAGS           EXT2_IOC_GETFLAGS
+#define REISERFS_IOC_SETFLAGS           EXT2_IOC_SETFLAGS
+#define REISERFS_IOC_GETVERSION 	EXT2_IOC_GETVERSION
+#define REISERFS_IOC_SETVERSION         EXT2_IOC_SETVERSION
  			         
 #endif /* _LINUX_REISER_FS_H */
 
diff -urN linux-2.4.19-pre2/include/linux/reiserfs_fs_i.h linux-2.4.19-pre3/include/linux/reiserfs_fs_i.h
--- linux-2.4.19-pre2/include/linux/reiserfs_fs_i.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre3/include/linux/reiserfs_fs_i.h	Mon Mar 11 14:13:31 2002
@@ -33,6 +33,9 @@
 
     __u32 i_first_direct_byte; // offset of first byte stored in direct item.
 
+    /* copy of persistent inode flags read from sd_attrs. */
+    __u32 i_attrs;
+
     int i_prealloc_block; /* first unused block of a sequence of unused blocks */
     int i_prealloc_count; /* length of that sequence */
     struct list_head i_prealloc_list;	/* per-transaction list of inodes which
diff -urN linux-2.4.19-pre2/include/linux/reiserfs_fs_sb.h linux-2.4.19-pre3/include/linux/reiserfs_fs_sb.h
--- linux-2.4.19-pre2/include/linux/reiserfs_fs_sb.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/include/linux/reiserfs_fs_sb.h	Mon Mar 11 14:13:31 2002
@@ -61,9 +61,19 @@
                                    superblock. -Hans */
   __u16 s_reserved;
   __u32 s_inode_generation;
-  char s_unused[124] ;			/* zero filled by mkreiserfs */
+  __u32 s_flags;		       /* Right now used only by inode-attributes, if enabled */
+  unsigned char s_uuid[16];            /* filesystem unique identifier */
+  unsigned char s_label[16];           /* filesystem volume label */
+  char s_unused[88] ;                  /* zero filled by mkreiserfs and
+                                        * reiserfs_convert_objectid_map_v1()
+                                        * so any additions must be updated
+                                        * there as well. */
 } __attribute__ ((__packed__));
 
+typedef enum {
+  reiserfs_attrs_cleared       = 0x00000001,
+} reiserfs_super_block_flags;
+
 #define SB_SIZE (sizeof(struct reiserfs_super_block))
 /* struct reiserfs_super_block accessors/mutators
  * since this is a disk structure, it will always be in 
@@ -330,6 +340,12 @@
   stat_cnt_t search_by_key_fs_changed;
   stat_cnt_t search_by_key_restarted;
 
+  stat_cnt_t insert_item_restarted;
+  stat_cnt_t paste_into_item_restarted;
+  stat_cnt_t cut_from_item_restarted;
+  stat_cnt_t delete_solid_item_restarted;
+  stat_cnt_t delete_item_restarted;
+
   stat_cnt_t leaked_oid;
   stat_cnt_t leaves_removable;
 
@@ -472,6 +488,8 @@
 #define REISERFS_TEST3 13
 #define REISERFS_TEST4 14 
 
+#define REISERFS_ATTRS (15)
+
 #define reiserfs_r5_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_R5_HASH))
 #define reiserfs_rupasov_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_RUPASOV_HASH))
 #define reiserfs_tea_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_TEA_HASH))
@@ -484,6 +502,7 @@
 #define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
 #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
+#define reiserfs_attrs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_ATTRS))
 #define old_format_only(s) ((s)->u.reiserfs_sb.s_properties & (1 << REISERFS_3_5))
 #define convert_reiserfs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT))
 
diff -urN linux-2.4.19-pre2/include/linux/sched.h linux-2.4.19-pre3/include/linux/sched.h
--- linux-2.4.19-pre2/include/linux/sched.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/linux/sched.h	Mon Mar 11 14:13:31 2002
@@ -612,6 +612,7 @@
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *);
+extern void sig_exit(int, int, struct siginfo *);
 extern int dequeue_signal(sigset_t *, siginfo_t *);
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
@@ -872,9 +873,14 @@
 #define for_each_task(p) \
 	for (p = &init_task ; (p = p->next_task) != &init_task ; )
 
+#define for_each_thread(task) \
+	for (task = next_thread(current) ; task != current ; task = next_thread(task))
+
 #define next_thread(p) \
 	list_entry((p)->thread_group.next, struct task_struct, thread_group)
 
+#define thread_group_leader(p)	(p->pid == p->tgid)
+
 static inline void del_from_runqueue(struct task_struct * p)
 {
 	nr_running--;
diff -urN linux-2.4.19-pre2/include/linux/skbuff.h linux-2.4.19-pre3/include/linux/skbuff.h
--- linux-2.4.19-pre2/include/linux/skbuff.h	Thu Nov 22 11:46:26 2001
+++ linux-2.4.19-pre3/include/linux/skbuff.h	Mon Mar 11 14:13:31 2002
@@ -588,7 +588,7 @@
 
 static inline struct sk_buff *skb_dequeue(struct sk_buff_head *list)
 {
-	long flags;
+	unsigned long flags;
 	struct sk_buff *result;
 
 	spin_lock_irqsave(&list->lock, flags);
@@ -737,7 +737,7 @@
 
 static inline struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
 {
-	long flags;
+	unsigned long flags;
 	struct sk_buff *result;
 
 	spin_lock_irqsave(&list->lock, flags);
diff -urN linux-2.4.19-pre2/include/linux/sysctl.h linux-2.4.19-pre3/include/linux/sysctl.h
--- linux-2.4.19-pre2/include/linux/sysctl.h	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/include/linux/sysctl.h	Mon Mar 11 14:13:31 2002
@@ -140,9 +140,9 @@
 	VM_PAGERDAEMON=8,	/* struct: Control kswapd behaviour */
 	VM_PGT_CACHE=9,		/* struct: Set page table cache parameters */
 	VM_PAGE_CLUSTER=10,	/* int: set number of pages to swap together */
-       VM_MIN_READAHEAD=12,    /* Min file readahead */
-       VM_MAX_READAHEAD=13,     /* Max file readahead */
-	VM_MAX_MAP_COUNT=19	/* int: Maximum number of active map areas */
+	VM_MAX_MAP_COUNT=11,	/* int: Maximum number of active map areas */
+	VM_MIN_READAHEAD=12,    /* Min file readahead */
+	VM_MAX_READAHEAD=13,    /* Max file readahead */
 };
 
 
diff -urN linux-2.4.19-pre2/include/net/irda/irlap.h linux-2.4.19-pre3/include/net/irda/irlap.h
--- linux-2.4.19-pre2/include/net/irda/irlap.h	Thu Sep 13 16:26:52 2001
+++ linux-2.4.19-pre3/include/net/irda/irlap.h	Mon Mar 11 14:13:31 2002
@@ -11,6 +11,7 @@
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
+ *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -44,6 +45,7 @@
 #define LAP_ADDR_HEADER 1  /* IrLAP Address Header */
 #define LAP_CTRL_HEADER 1  /* IrLAP Control Header */
 
+/* May be different when we get VFIR */
 #define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
 
 #define BROADCAST  0xffffffff /* Broadcast device address */
@@ -210,9 +212,8 @@
 void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
 void irlap_apply_default_connection_parameters(struct irlap_cb *self);
 void irlap_apply_connection_parameters(struct irlap_cb *self, int now);
-void irlap_set_local_busy(struct irlap_cb *self, int status);
 
-#define IRLAP_GET_HEADER_SIZE(self) 2 /* Will be different when we get VFIR */
+#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
 #endif
diff -urN linux-2.4.19-pre2/include/net/irda/irlap_event.h linux-2.4.19-pre3/include/net/irda/irlap_event.h
--- linux-2.4.19-pre2/include/net/irda/irlap_event.h	Fri Nov  9 14:22:17 2001
+++ linux-2.4.19-pre3/include/net/irda/irlap_event.h	Mon Mar 11 14:13:31 2002
@@ -134,7 +134,6 @@
 
 void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, 
 		    struct sk_buff *skb, struct irlap_info *info);
-void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state);
 void irlap_print_event(IRLAP_EVENT event);
 
 extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb);
diff -urN linux-2.4.19-pre2/init/main.c linux-2.4.19-pre3/init/main.c
--- linux-2.4.19-pre2/init/main.c	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/init/main.c	Mon Mar 11 14:13:31 2002
@@ -348,7 +348,6 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-	unsigned long mempages;
 	extern char saved_command_line[];
 /*
  * Interrupts are still disabled. Do necessary setups, then
@@ -399,13 +398,21 @@
 	kmem_cache_sizes_init();
 	pgtable_cache_init();
 
-	mempages = num_physpages;
-
-	fork_init(mempages);
+	/*
+	 * For architectures that have highmem, num_mappedpages represents
+	 * the amount of memory the kernel can use.  For other architectures
+	 * it's the same as the total pages.  We need both numbers because
+	 * some subsystems need to initialize based on how much memory the
+	 * kernel can use.
+	 */
+	if (num_mappedpages == 0)
+		num_mappedpages = num_physpages;
+  
+	fork_init(num_mappedpages);
 	proc_caches_init();
-	vfs_caches_init(mempages);
-	buffer_init(mempages);
-	page_cache_init(mempages);
+	vfs_caches_init(num_physpages);
+	buffer_init(num_physpages);
+	page_cache_init(num_physpages);
 #if defined(CONFIG_ARCH_S390)
 	ccwcache_init();
 #endif
diff -urN linux-2.4.19-pre2/kernel/fork.c linux-2.4.19-pre3/kernel/fork.c
--- linux-2.4.19-pre2/kernel/fork.c	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/kernel/fork.c	Mon Mar 11 14:13:31 2002
@@ -710,10 +710,10 @@
 	/* Need tasklist lock for parent etc handling! */
 	write_lock_irq(&tasklist_lock);
 
-	/* CLONE_PARENT and CLONE_THREAD re-use the old parent */
+	/* CLONE_PARENT re-uses the old parent */
 	p->p_opptr = current->p_opptr;
 	p->p_pptr = current->p_pptr;
-	if (!(clone_flags & (CLONE_PARENT | CLONE_THREAD))) {
+	if (!(clone_flags & CLONE_PARENT)) {
 		p->p_opptr = current;
 		if (!(p->ptrace & PT_PTRACED))
 			p->p_pptr = current;
diff -urN linux-2.4.19-pre2/kernel/panic.c linux-2.4.19-pre3/kernel/panic.c
--- linux-2.4.19-pre2/kernel/panic.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre3/kernel/panic.c	Mon Mar 11 14:13:31 2002
@@ -96,6 +96,10 @@
 #endif
 	sti();
 	for(;;) {
+#if defined(__i386__) && defined(CONFIG_VT) 
+		extern void panic_blink(void);
+		panic_blink(); 
+#endif
 		CHECK_EMERGENCY_SYNC
 	}
 }
diff -urN linux-2.4.19-pre2/kernel/pm.c linux-2.4.19-pre3/kernel/pm.c
--- linux-2.4.19-pre2/kernel/pm.c	Fri Apr  6 10:51:19 2001
+++ linux-2.4.19-pre3/kernel/pm.c	Mon Mar 11 14:13:31 2002
@@ -162,7 +162,7 @@
 	case PM_SUSPEND:
 	case PM_RESUME:
 		prev_state = dev->state;
-		next_state = (int) data;
+		next_state = (unsigned long) data;
 		if (prev_state != next_state) {
 			if (dev->callback)
 				status = (*dev->callback)(dev, rqst, data);
diff -urN linux-2.4.19-pre2/kernel/ptrace.c linux-2.4.19-pre3/kernel/ptrace.c
--- linux-2.4.19-pre2/kernel/ptrace.c	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre3/kernel/ptrace.c	Mon Mar 11 14:13:31 2002
@@ -164,7 +164,7 @@
 		if (write) {
 			memcpy(maddr + offset, buf, bytes);
 			flush_page_to_ram(page);
-			flush_icache_page(vma, page);
+			flush_icache_user_range(vma, page, addr, len);
 		} else {
 			memcpy(buf, maddr + offset, bytes);
 			flush_page_to_ram(page);
diff -urN linux-2.4.19-pre2/kernel/signal.c linux-2.4.19-pre3/kernel/signal.c
--- linux-2.4.19-pre2/kernel/signal.c	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/kernel/signal.c	Mon Mar 11 14:13:31 2002
@@ -142,6 +142,35 @@
 	}
 }
 
+/*
+ * sig_exit - cause the current task to exit due to a signal.
+ */
+
+void
+sig_exit(int sig, int exit_code, struct siginfo *info)
+{
+	struct task_struct *t;
+
+	sigaddset(&current->pending.signal, sig);
+	recalc_sigpending(current);
+	current->flags |= PF_SIGNALED;
+
+	/* Propagate the signal to all the tasks in
+	 *  our thread group
+	 */
+	if (info && (unsigned long)info != 1
+	    && info->si_code != SI_TKILL) {
+		read_lock(&tasklist_lock);
+		for_each_thread(t) {
+			force_sig_info(sig, info, t);
+		}
+		read_unlock(&tasklist_lock);
+	}
+
+	do_exit(exit_code);
+	/* NOTREACHED */
+}
+
 /* Notify the system that a driver wants to block all signals for this
  * process, and wants to be notified if any signals at all were to be
  * sent/acted upon.  If the notifier routine returns non-zero, then the
@@ -592,7 +621,7 @@
 		retval = -ESRCH;
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pgrp == pgrp) {
+			if (p->pgrp == pgrp && thread_group_leader(p)) {
 				int err = send_sig_info(sig, info, p);
 				if (retval)
 					retval = err;
@@ -639,8 +668,15 @@
 	read_lock(&tasklist_lock);
 	p = find_task_by_pid(pid);
 	error = -ESRCH;
-	if (p)
+	if (p) {
+		if (!thread_group_leader(p)) {
+                       struct task_struct *tg;
+                       tg = find_task_by_pid(p->tgid);
+                       if (tg)
+                               p = tg;
+                }
 		error = send_sig_info(sig, info, p);
+	}
 	read_unlock(&tasklist_lock);
 	return error;
 }
@@ -663,7 +699,7 @@
 
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pid > 1 && p != current) {
+			if (p->pid > 1 && p != current && thread_group_leader(p)) {
 				int err = send_sig_info(sig, info, p);
 				++count;
 				if (err != -EPERM)
@@ -988,6 +1024,36 @@
 	return kill_something_info(sig, &info, pid);
 }
 
+/*
+ *  Kill only one task, even if it's a CLONE_THREAD task.
+ */
+asmlinkage long
+sys_tkill(int pid, int sig)
+{
+       struct siginfo info;
+       int error;
+       struct task_struct *p;
+
+       /* This is only valid for single tasks */
+       if (pid <= 0)
+           return -EINVAL;
+
+       info.si_signo = sig;
+       info.si_errno = 0;
+       info.si_code = SI_TKILL;
+       info.si_pid = current->pid;
+       info.si_uid = current->uid;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+       error = -ESRCH;
+       if (p) {
+               error = send_sig_info(sig, &info, p);
+       }
+       read_unlock(&tasklist_lock);
+       return error;
+}
+
 asmlinkage long
 sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo)
 {
diff -urN linux-2.4.19-pre2/mm/memory.c linux-2.4.19-pre3/mm/memory.c
--- linux-2.4.19-pre2/mm/memory.c	Mon Mar 11 14:13:23 2002
+++ linux-2.4.19-pre3/mm/memory.c	Mon Mar 11 14:13:31 2002
@@ -52,6 +52,7 @@
 
 unsigned long max_mapnr;
 unsigned long num_physpages;
+unsigned long num_mappedpages;
 void * high_memory;
 struct page *highmem_start_page;
 
diff -urN linux-2.4.19-pre2/net/irda/af_irda.c linux-2.4.19-pre3/net/irda/af_irda.c
--- linux-2.4.19-pre2/net/irda/af_irda.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre3/net/irda/af_irda.c	Mon Mar 11 14:13:31 2002
@@ -1025,29 +1025,27 @@
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
-		
-	cli();	/* To avoid races on the sleep */
-	
-	/* A Connect Ack with Choke or timeout or failed routing will go to
-	 * closed.  */
+
+	/* Here, there is a race condition : the state may change between
+	 * our test and the sleep, via irda_connect_confirm().
+	 * The way to workaround that is to sleep with a timeout, so that
+	 * we don't sleep forever and check the state when waking up.
+	 * 50ms is plenty good enough, because the LAP is already connected.
+	 * Jean II */
 	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on(sk->sleep);
+		interruptible_sleep_on_timeout(sk->sleep, HZ/20);
 		if (signal_pending(current)) {
-			sti();
 			return -ERESTARTSYS;
 		}
 	}
 	
 	if (sk->state != TCP_ESTABLISHED) {
-		sti();
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
 	
 	sock->state = SS_CONNECTED;
 	
-	sti();
-	
 	/* At this point, IrLMP has assigned our source address */
 	self->saddr = irttp_get_saddr(self->tsap);
 
diff -urN linux-2.4.19-pre2/net/irda/irlap.c linux-2.4.19-pre3/net/irda/irlap.c
--- linux-2.4.19-pre2/net/irda/irlap.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre3/net/irda/irlap.c	Mon Mar 11 14:13:31 2002
@@ -131,7 +131,7 @@
 	/* FIXME: should we get our own field? */
 	dev->atalk_ptr = self;
 
-	irlap_next_state(self, LAP_OFFLINE);
+	self->state = LAP_OFFLINE;
 
 	/* Initialize transmit queue */
 	skb_queue_head_init(&self->txq);
@@ -155,7 +155,7 @@
 
 	self->N3 = 3; /* # connections attemts to try before giving up */
 	
-	irlap_next_state(self, LAP_NDM);
+	self->state = LAP_NDM;
 
 	hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);
 
@@ -346,25 +346,21 @@
 	else
 		skb->data[1] = I_FRAME;
 
+	/* Add at the end of the queue (keep ordering) - Jean II */
+	skb_queue_tail(&self->txq, skb);
+
 	/* 
 	 *  Send event if this frame only if we are in the right state 
 	 *  FIXME: udata should be sent first! (skb_queue_head?)
 	 */
   	if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
-		/*
-		 *  Check if the transmit queue contains some unsent frames,
-		 *  and if so, make sure they are sent first
-		 */
-		if (!skb_queue_empty(&self->txq)) {
-			skb_queue_tail(&self->txq, skb);
-			skb = skb_dequeue(&self->txq);
-			
-			ASSERT(skb != NULL, return;);
-		}
-		irlap_do_event(self, SEND_I_CMD, skb, NULL);
-		kfree_skb(skb);
-	} else
-		skb_queue_tail(&self->txq, skb);
+		/* If we are not already processing the Tx queue, trigger
+		 * transmission immediately - Jean II */
+		if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy))
+			irlap_do_event(self, DATA_REQUEST, skb, NULL);
+		/* Otherwise, the packets will be sent normally at the
+		 * next pf-poll - Jean II */
+	}
 }
 
 /*
@@ -1013,6 +1009,7 @@
 	self->window_size = self->qos_tx.window_size.value;
 	self->window      = self->qos_tx.window_size.value;
 
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 	/*
 	 *  Calculate how many bytes it is possible to transmit before the
 	 *  link must be turned around
@@ -1020,6 +1017,8 @@
 	self->line_capacity = 
 		irlap_max_line_capacity(self->qos_tx.baud_rate.value,
 					self->qos_tx.max_turn_time.value);
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 
 	
 	/* 
@@ -1082,24 +1081,6 @@
 	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
 }
 
-/*
- * Function irlap_set_local_busy (self, status)
- *
- *    
- *
- */
-void irlap_set_local_busy(struct irlap_cb *self, int status)
-{
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
-	self->local_busy = status;
-	
-	if (status)
-		IRDA_DEBUG(0, __FUNCTION__ "(), local busy ON\n");
-	else
-		IRDA_DEBUG(0, __FUNCTION__ "(), local busy OFF\n");
-}
-
 #ifdef CONFIG_PROC_FS
 /*
  * Function irlap_proc_read (buf, start, offset, len, unused)
diff -urN linux-2.4.19-pre2/net/irda/irlap_event.c linux-2.4.19-pre3/net/irda/irlap_event.c
--- linux-2.4.19-pre2/net/irda/irlap_event.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre3/net/irda/irlap_event.c	Mon Mar 11 14:13:31 2002
@@ -252,6 +252,9 @@
 		 * that will change the state away form XMIT
 		 */
 		if (skb_queue_len(&self->txq)) {
+			/* Prevent race conditions with irlap_data_request() */
+			self->local_busy = TRUE;
+
 			/* Try to send away all queued data frames */
 			while ((skb = skb_dequeue(&self->txq)) != NULL) {
 				ret = (*state[self->state])(self, SEND_I_CMD,
@@ -260,6 +263,8 @@
 				if (ret == -EPROTO)
 					break; /* Try again later! */
 			}
+			/* Finished transmitting */
+			self->local_busy = FALSE;
 		} else if (self->disconnect_pending) {
 			self->disconnect_pending = FALSE;
 			
@@ -282,25 +287,15 @@
  *    Switches state and provides debug information
  *
  */
-void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
+static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
 {	
+	/*
 	if (!self || self->magic != LAP_MAGIC)
 		return;
 	
 	IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
-
+	*/
 	self->state = state;
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
-	/*
-	 *  If we are swithing away from a XMIT state then we are allowed to 
-	 *  transmit a maximum number of bytes again when we enter the XMIT 
-	 *  state again. Since its possible to "switch" from XMIT to XMIT,
-	 *  we cannot do this when swithing into the XMIT state :-)
-	 */
-	if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
-		self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 }
 
 /*
@@ -1017,6 +1012,12 @@
 		IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n",
 			   jiffies);
 		irlap_send_rr_frame(self, CMD_FRAME);
+		/* Return to NRM properly - Jean II  */
+		self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+		/* Allowed to transmit a maximum number of bytes again. */
+		self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 		irlap_start_final_timer(self, self->final_timeout);
 		irlap_next_state(self, LAP_NRM_P);
 		break;
@@ -1029,6 +1030,10 @@
 		self->retry_count = 0;
 		irlap_next_state(self, LAP_PCLOSE);
 		break;
+	case DATA_REQUEST:
+		/* Nothing to do, irlap_do_event() will send the packet
+		 * when we return... - Jean II */
+		break;
 	default:
 		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
 			   irlap_event[event]);
@@ -1645,12 +1650,17 @@
 			 */
 			if (skb->len > self->bytes_left) {
 				skb_queue_head(&self->txq, skb_get(skb));
+
 				/*
 				 *  Switch to NRM_S, this is only possible
 				 *  when we are in secondary mode, since we 
 				 *  must be sure that we don't miss any RR
 				 *  frames
 				 */
+				self->window = self->window_size;
+				self->bytes_left = self->line_capacity;
+				irlap_start_wd_timer(self, self->wd_timeout);
+
 				irlap_next_state(self, LAP_NRM_S);
 
 				return -EPROTO; /* Try again later */
@@ -1688,6 +1698,10 @@
 		irlap_start_wd_timer(self, self->wd_timeout);
 		irlap_next_state(self, LAP_SCLOSE);
 		break;
+	case DATA_REQUEST:
+		/* Nothing to do, irlap_do_event() will send the packet
+		 * when we return... - Jean II */
+		break;
 	default:
 		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
 			   irlap_event[event]);
diff -urN linux-2.4.19-pre2/net/irda/irlap_frame.c linux-2.4.19-pre3/net/irda/irlap_frame.c
--- linux-2.4.19-pre2/net/irda/irlap_frame.c	Fri Nov  9 14:22:17 2001
+++ linux-2.4.19-pre3/net/irda/irlap_frame.c	Mon Mar 11 14:13:31 2002
@@ -768,6 +768,9 @@
 {
 	struct sk_buff *tx_skb;
 
+	/* Stop P timer */
+	del_timer(&self->poll_timer);
+		
 	/* Is this reliable or unreliable data? */
 	if (skb->data[1] == I_FRAME) {
 		
@@ -793,23 +796,15 @@
 		 *  skb, since retransmitted need to set or clear the poll
 		 *  bit depending on when they are sent.  
 		 */
-		/* Stop P timer */
-		del_timer(&self->poll_timer);
-		
 		tx_skb->data[1] |= PF_BIT;
 		
 		self->vs = (self->vs + 1) % 8;
 		self->ack_required = FALSE;
-		self->window = self->window_size;
-
-		irlap_start_final_timer(self, self->final_timeout);
 
 		irlap_send_i_frame(self, tx_skb, CMD_FRAME);
 	} else {
 		IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
 
-		del_timer(&self->poll_timer);
-
 		if (self->ack_required) {
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
 			irlap_send_rr_frame(self, CMD_FRAME);
@@ -818,9 +813,15 @@
 			skb->data[1] |= PF_BIT;
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
 		}
-		self->window = self->window_size;
-		irlap_start_final_timer(self, self->final_timeout);
 	}
+
+	self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	/* We are allowed to transmit a maximum number of bytes again. */
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+
+	irlap_start_final_timer(self, self->final_timeout);
 }
 
 /*
@@ -858,11 +859,8 @@
 		tx_skb->data[1] |= PF_BIT;
 		
 		self->vs = (self->vs + 1) % 8; 
-		self->window = self->window_size;
 		self->ack_required = FALSE;
 		
-		irlap_start_wd_timer(self, self->wd_timeout);
-
 		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
 	} else {
 		if (self->ack_required) {
@@ -873,10 +871,15 @@
 			skb->data[1] |= PF_BIT;
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
 		}
-		self->window = self->window_size;
-
-		irlap_start_wd_timer(self, self->wd_timeout);
 	}
+
+	self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	/* We are allowed to transmit a maximum number of bytes again. */
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+
+	irlap_start_wd_timer(self, self->wd_timeout);
 }
 
 /*
diff -urN linux-2.4.19-pre2/net/irda/irnet/irnet.h linux-2.4.19-pre3/net/irda/irnet/irnet.h
--- linux-2.4.19-pre2/net/irda/irnet/irnet.h	Fri Dec 21 09:42:06 2001
+++ linux-2.4.19-pre3/net/irda/irnet/irnet.h	Mon Mar 11 14:13:31 2002
@@ -206,6 +206,11 @@
  *	  just after clearing it. *blush*.
  *	o Use newly created irttp_listen() to fix potential crash when LAP
  *	  destroyed before irnet module removed.
+ *
+ * v10 - 4.3.2 - Jean II
+ *	o When receiving a disconnect indication, don't reenable the
+ *	  PPP Tx queue, this will trigger a reconnect. Instead, close
+ *	  the channel, which will kill pppd...
  */
 
 /***************************** INCLUDES *****************************/
diff -urN linux-2.4.19-pre2/net/irda/irnet/irnet_irda.c linux-2.4.19-pre3/net/irda/irnet/irnet_irda.c
--- linux-2.4.19-pre2/net/irda/irnet/irnet_irda.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.19-pre3/net/irda/irnet/irnet_irda.c	Mon Mar 11 14:13:31 2002
@@ -1122,9 +1122,10 @@
       irttp_close_tsap(self->tsap);
       self->tsap = NULL;
 
-      /* Flush (drain) ppp_generic Tx queue (most often we have blocked it) */
+      /* Cleanup & close the PPP channel, which will kill pppd and the rest */
       if(self->ppp_open)
-	ppp_output_wakeup(&self->chan);
+	ppp_unregister_channel(&self->chan);
+      self->ppp_open = 0;
     }
   /* Cleanup the socket in case we want to reconnect */
   self->stsap_sel = 0;
